Skip to content

Free Access Based on Shopify Plan

Luke Walsh edited this page Dec 18, 2022 · 1 revision

As raised in issue #63, some paid apps may require a shop to gain free access during install. Plans such as Shopify staff or affiliates.

You may utilize the After Authentication Job to accomplish this.

Setup

First, run through the After Authentication Job setup process.

Be sure to set the config for the job to be inline, example: 'inline' => true.

Once completed, you should have a AfterAuthenticateJob in App\Jobs and the config properly setup.

Implementation

You may open up App\Jobs\AfterAuthenticateJob and replace it with these contents:

<?php

namespace App\Jobs;

use Osiset\ShopifyApp\Contracts\ShopModel;

class AfterAuthenticateJob
{
    /**
     * Shop's instance.
     *
     * @var ShopModel
     */
    protected $shop;

    /**
     * Create a new job instance.
     *
     * @param ShopModel $shop The shop's object
     *
     * @return void
     */
    public function __construct(ShopModel $shop)
    {
        $this->shop = $shop;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        if (!$this->shop->isGrandfathered()) {
            $planName = $this->shop->api()->rest('GET', '/admin/shop.json')->body->shop->plan_name;
            if ($planName === 'affiliate' || $planName === 'staff_business') {
                 $this->shop->shopify_grandfathered = true;
                 $this->shop->save();
            }
        }
    }
}

Simply modify the second if statement in the handle() method to check which plans you wish to allow free access on install, and you're done.

@tobiasdalhof has found the following plans for Shopify stores, as a reference:

"affiliate",
"staff",
"professional",
"custom",
"shopify_plus",
"unlimited",
"basic",
"cancelled",
"staff_business",
"trial",
"dormant",
"frozen",
"singtel_unlimited",
"npo_lite",
"singtel_professional",
"singtel_trial",
"npo_full",
"business",
"singtel_basic",
"uafrica_professional",
"sales_training",
"singtel_starter",
"uafrica_basic",
"fraudulent",
"enterprise",
"starter",
"comped",
"shopify_alumni"

Flow

With the job enabled and set to run inline... it will fire on every initial auth action; which happens on install, or when clicking the app from the Apps dashboard.

This job will fire directly after auth and before the billing screen, it will check if the shop's plan matches, and if so, it will set the shop as grandfathered to ensure the shop skips the billing process always.

Notes

Since this job will fire every auth and not just once, you may wish to implement logic to prevent it from running more than once. You can do it with a number of ways, but a couple suggestions (untested):

a) Check the created time of the shop is equal to today, if so, run the code, example:

    # ...
    use Carbon\Carbon;
    # ...

    # Modify handle in App\Jobs\AfterAuthenticateJob
    public function handle()
    {
        if ($this->shop->created_at->diffInDays(Carbon::today()) !== 0) {
            // Shop is older than a day, we should've ran this by now, kill it
            return;
        }

        if (!$this->shop->isGrandfathered()) {
            $planName = $this->shop->api()->rest('GET', '/admin/shop.json')->body->shop->plan_name;
            if ($planName === 'affiliate' || $planName === 'staff_business') {
                 $this->shop->shopify_grandfathered = true;
                 $this->shop->save();
            }
        }
    }

b) Track the job ran with "finished_setup" per @tobiasdalhof:

Create a migration, database/migrations/AddFinishedSetupToShopsTable.php:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddFinishedSetupToUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->boolean('finished_setup')->default(false);
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('finished_setup');
        });
    }
}

Run the migration via php artisan migrate. Then, modify the AfterAuthenticateJob file:

    # Modify handle in App\Jobs\AfterAuthenticateJob
    public function handle()
    {
        if ($this->shop->finished_setup) {
            // Setup has finished, this should've ran by now, kill it
            return;
        }

        if (!$this->shop->isGrandfathered()) {
            $planName = $this->shop->api()->rest('GET', '/admin/shop.json')->body->shop->plan_name;
            if ($planName === 'affiliate' || $planName === 'staff_business') {
                 $this->shop->shopify_grandfathered = true;
                 $this->shop->finished_setup = true;
                 $this->shop->save();
            }
        }
    }