wazza/sync-model-to-crm

辅助包,用于简化 Laravel 模型(例如 `User`、`Entity` 等)与外部 CRM 对象(例如 HubSpot/Pipedrive 的 `Contact`、`Company` 等)的数据同步

v1.0.0-beta 2024-09-06 12:01 UTC

This package is auto-updated.

Last update: 2024-09-06 12:01:49 UTC


README

GitHub issues GitHub stars GitHub license

同步模型到远程 CRM 对象

一个库,可以将任何定义的数据库表属性/关联(在模型内部)同步到外部 CRM 提供商,例如 HubSpotPipedrive 等。

步骤:在 Laravel 模型中添加一些属性配置,通过观察器或模型修改器配置同步触发,并监控日志以查看数据如何自动与 HubSpot 对象(如客户)同步。您还可以通过事件作业触发同步过程。

当前支持

  • HubSpot
    • 本地 UserContact 对象的同步。
    • 本地 EntityCompany 对象的同步。
    • ContactCompany 记录之间的关联。
    • 即将推出... Deal & Ticket 对象。
  • 未来支持
    • Pipedrive
    • Salesforce
    • ZohoCrm
    • 等。

概述

这个库的目的是让开发者能够轻松地在每个适用的模型(如 UserEntityOrder 等)中定义哪些属性应该与哪个 CRM 提供商和环境同步。

在每次首次成功同步后,CRM 对象的主键将存储在映射表中,与本地表的主键相对应。这允许未来更改时更快地加载。

使用 7 个属性更新您的模型,以定义第三方 CRM 同步的规则

  • @var string|array|null $syncModelCrmEnvironment;

    如果没有提供,将使用 config('sync_modeltocrm.api.environment')

  • @var array $syncModelCrmPropertyMapping; *必需
  • @var array $syncModelCrmUniqueSearch; *必需
  • @var string $syncModelCrmRelatedObject;

    如果没有提供,将使用 config('sync_modeltocrm.api.providers.{provider}.object_table_mapping')

  • @var array $syncModelCrmDeleteRules; *必需用于删除操作
  • @var array $syncModelCrmActiveRules; *必需用于恢复操作
  • @var array $syncModelCrmAssociateRules; *必需当关联为 true 时

以下是一个示例

  1. User 模型将同步到 SandboxProduction HubSpot 环境($syncModelCrmEnvironment)。
  2. 它将只同步 nameemail 属性到 HubSpot 对应的 firstnameemail 字段($syncModelCrmPropertyMapping)。
  3. 当没有内部映射已存储时,将使用 email 属性($syncModelCrmUniqueSearch)唯一加载 CRM 记录。
  4. 为了让脚本知道哪个远程 CRM 对象与用户模型相关,必须将 contact ($syncModelCrmRelatedObject) 定义为远程项。
  5. $syncModelCrmDeleteRules)属性用于指导 CRM 当本地记录被删除/移除时采取什么操作。例如,当本地启用 SoftDeletes 时,CRM 将使用 soft_delete 规则更新 CRM 记录,或者将记录存档在 CRM 中。
  6. 与上述相反,($syncModelCrmActiveRules) 将用于定义删除的记录再次激活时要采取的操作。
  7. 最后,非必填属性 ($syncModelCrmAssociateRules) 用于定义对象之间的关系(关联)。例如,从 userentity
<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use App\Models\Entity;
use Illuminate\Database\Eloquent\SoftDeletes;
use Wazza\SyncModelToCrm\Http\Controllers\CrmProviders\HubSpotController;
use Wazza\SyncModelToCrm\Traits\crmTrait;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable, SoftDeletes;

    // include this if you wish to use the `Mutators function` or
    // $this->syncToCrm() directly as appose to the observer method
    use crmTrait;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
        'password' => 'hashed',
    ];

    /**
     * Function that will be used to return the relationship data
     * @return type
     */
    public function entity()
    {
        return $this->belongsTo(Entity::class)->withTrashed();
    }

    // --------------------------------------------------------------
    // Sync Model to CRM
    // --------------------------------------------------------------

    /**
     * The CRM provider environment/s to use (e.g. production, sandbox, etc.)
     * Use an array to sync to multiple environments.
     * `null` (or not defined) will take the default from the config file.
     *
     * @var string|array|null
     */
    public $syncModelCrmEnvironment = ['sandbox']; // ..or ['sandbox','production']

    /**
     * Mapping array for local and CRM properties
     * This will be the primary property used to cycle through the crm providers
     * and properties to sync the model to the CRM.
     * Required - if not provided, the sync will process will be skipped (no Exceptions will be thrown)
     *
     * @var array
     */
    public $syncModelCrmPropertyMapping = [
        'hubspot' => [
            'name' => 'firstname',
            'email' => 'email',
            // ... add all the properties that you would like to sync
        ],
    ];

    /**
     * Unique filters for the CRM to locate the record if there is no internal mapping available.
     * Not required, but strongly encouraged to be configured as to avoid any duplicate record creation in the crm
     *
     * @var array
     */
    public $syncModelCrmUniqueSearch = [
        'hubspot' => [
            'email' => 'email', // this will ensure that the search filter is unique
        ],
    ];

    /**
     * The CRM object to sync this model to.
     * This is the CRM object type (e.g. contact, company, deal, etc.)
     * If this is null or not provided, the `object_table_mapping` key will be used from the config file.
     *
     * @var string
     */
    public $syncModelCrmRelatedObject = 'contact';

    /**
     * The CRM Delete rules to follow.
     * i.e. if Soft-delete is applicable, what should the CRM record be updated to?
     * if Hard-delete is used, the record will be deleted/archived in the CRM.
     *
     * @var array
     */
    public $syncModelCrmDeleteRules = [
        'hard_delete' => [
            'hubspot' => false,
        ],
        'soft_delete' => [
            'hubspot' => [
                'lifecyclestage' => 'other',
                'hs_lead_status' => 'DELETED',
            ],
        ]
    ];

    /**
     * The CRM Active/Restore rules to follow.
     * These will be the rules to follow for any new entries that are not soft-deleted.
     *
     * @var array
     */
    public $syncModelCrmActiveRules = [
        'hubspot' => [
            'lifecyclestage' => 'customer',
            'hs_lead_status' => 'OPEN',
        ],
    ];

    /**
     * The CRM Associations to sync.
     * This is used to associate the model with other CRM objects.
     *
     * @var array
     */
    public $syncModelCrmAssociateRules = [
        [
            'assocMethod'   => 'entity', // App\Models\Entity::class
            'provider' => [
                'hubspot' => [
                    [
                        'association_category' => HubSpotController::ASSOCIATION_CATEGORY__HUBSPOT_DEFINED,
                        'association_type_id' => HubSpotController::ASSOCIATION_TYPE_ID__CONTACT_TO_COMPANY_PRIMARY,
                    ],
                    [
                        'association_category' => HubSpotController::ASSOCIATION_CATEGORY__HUBSPOT_DEFINED,
                        'association_type_id' => HubSpotController::ASSOCIATION_TYPE_ID__CONTACT_TO_COMPANY,
                    ],
                ],
            ],
        ],
    ];

    // --------------------------------------------------------------
    // Custom Methods to initiate a sync
    // --------------------------------------------------------------

    /**
     * (1) Register the observer in the AppServiceProvider boot method
     *
     * public function boot(): void
     *  {
     *      // register the observer/s
     *      // ...refer the the template examples in the sync-model-to-crm repo for a observer working copy
     *      \App\Models\User::observe(\App\Observers\UserObserver::class);
     *  }
     */


    /**
     * (2) Mutators function (Laravel 5.4 or above)
     *
     * Laravel provides mutators which are methods that can be defined on a model to modify
     * attributes before they are saved. You can create a custom mutator named save that
     * first calls the original save method using parent::save() and then performs your
     * additional action.
     *
     * @param array $options
     * @return void
     */
    public function save(array $options = [])
    {
        parent::save($options);

        // lets call the syncModelToCrm method to sync the model to the CRM.
        // refer to the trait for all the available methods
        // $this->syncToCrmPatch(); -- disabled as we are currently using the observer method
    }
}

用法

您可以使用几种方法来启动模型同步。

执行 (new CrmController())->setModel($user)->execute();

  1. 直接在控制器操作中。

  2. 在模型中使用特性作为类型化函数。

  3. 通过观察者。例如,在 UserObserver 中触发 save() 事件之后。(见下文)

    <?php
    
    namespace App\Observers;
    
    use App\Models\User;
    use Wazza\SyncModelToCrm\Http\Controllers\CrmController;
    use Illuminate\Contracts\Events\ShouldHandleEventsAfterCommit;
    
    /**
     * Register the observer in the AppServiceProvider boot method
     *
     * public function boot(): void
     *  {
     *      // register the observer/s
     *      \App\Models\User::observe(\App\Observers\UserObserver::class);
     *  }
     */
    class UserObserver implements ShouldHandleEventsAfterCommit
    {
        /**
        * Handle the User "created" event.
        */
        public function created(User $user): void
        {
            echo ('create...');
            (new CrmController())
                ->setModel($user)
                ->setAttemptCreate()
                ->execute(true);
            echo ('created...');
        }
    
        /**
        * Handle the User "updated" event.
        */
        public function updated(User $user): void
        {
            echo ('update...');
            (new CrmController())
                ->setModel($user)
                ->setAttemptUpdate()
                ->execute(true);
            echo ('updated...');
        }
    
        /**
        * Handle the User "deleted" event.
        * Run when a user is soft-deleted.
        */
        public function deleted(User $user)
        {
            echo ('delete...');
            (new CrmController())
                ->setModel($user)
                ->setAttemptDelete()
                ->execute();
            echo ('deleted...');
        }
    
        /**
        * Handle the User "restored" event.
        * Soft-delete has been reversed.
        */
        public function restored(User $user): void
        {
            echo ('restore...');
            (new CrmController())
                ->setModel($user)
                ->setAttemptRestore()
                ->execute();
            echo ('restored...');
        }
    
        /**
        * Handle the User "force deleted" event.
        */
        public function forceDeleted(User $user): void
        {
            echo ('forceDeleted...');
        }
    
        /**
        * Handle the User "saved" event.
        *
        */
        public function saved(User $user): void
        {
            echo ('saving...');
            (new CrmController())
                ->setModel($user)
                ->setAttemptAll() // open for anything...
                ->execute();
            echo ('saved...');
        }
    }
  4. 在事件作业中。这是一种将逻辑从保存事件中分离出来,并将同步放入作业队列以在记录保存后立即处理的好方法。

安装

PHP 8.1 是本项目的最低要求。

  1. 打开终端并要求包。

    composer require wazza/sync-model-to-crm
  2. 导航到您的 Laravel 项目的 config 目录并打开 app.php 文件。

    • app.php 文件中查找 providers 数组。

    • providers 数组中,添加以下行并保存:Wazza\SyncModelToCrm\Providers\SyncModelToCrmServiceProvider::class, 以下为示例

      'providers' => ServiceProvider::defaultProviders()->merge([
          /*
          * Package Service Providers...
          */
          Wazza\SyncModelToCrm\Providers\SyncModelToCrmServiceProvider::class, // <-- here
          Wazza\DomTranslate\Providers\DomTranslateServiceProvider::class,
      
          /*
          * Application Service Providers...
          */
          App\Providers\AppServiceProvider::class,
          App\Providers\AuthServiceProvider::class,
          // App\Providers\BroadcastServiceProvider::class,
          App\Providers\EventServiceProvider::class,
          App\Providers\RouteServiceProvider::class,
      ])->toArray(),
  3. 再次在终端中,通过运行以下命令完成设置:

    php artisan vendor:publish --tag="sync-modeltocrm-config"
    php artisan vendor:publish --tag="sync-modeltocrm-migrations"
    php artisan migrate
  4. 以下是您可以添加到 .env 配置文件中的一些环境键。如果您需要更多关于每个项目的信息,请参阅 config/sync_modeltocrm.php 配置文件。

    SYNC_MODEL_TO_CRM_HASH_SALT=Ey4cw2BHvi0HmGYjyqYr
    SYNC_MODEL_TO_CRM_HASH_ALGO=sha256
    SYNC_MODEL_TO_CRM_LOG_INDICATOR=sync-modeltocrm
    SYNC_MODEL_TO_CRM_LOG_LEVEL=3
    SYNC_MODEL_TO_CRM_PROVIDER=hubspot
    SYNC_MODEL_TO_CRM_ENVIRONMENT=sandbox
    SYNC_MODEL_TO_CRM_PROVIDER_HUBSPOT_SANDBOX_URI=https://api.hubapi.com/crm/v4/
    SYNC_MODEL_TO_CRM_PROVIDER_HUBSPOT_SANDBOX_TOKEN=xxx-xxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    
  5. 在修改完 env 变量后,运行 config:cache

    php artisan config:cache
  6. 完成。审查您可能想要更改的任何配置文件更改。配置文件已发布到主配置文件夹。

查看日志

根据您的日志级别(参考您的配置文件设置:1:高到 3:低),您的 Laravel 日志文件将写入更少或更多的信息。

您可以通过运行 tail -f {log path} 跟踪事务,甚至可以包含带有唯一事务 8 位代码的 grep

测试

运行以下命令以执行测试

./vendor/bin/pest

输出示例

   PASS  Tests\Unit\EnvTest
  ✓ it should have the correct environment variables set         1.11s

   PASS  Tests\Unit\ExampleTest
  ✓ it contains a successful example unit test                   0.33s

   PASS  Tests\Unit\ModelTest
  ✓ it can create a new SmtcExternalKeyLookup model record       0.31s
  ✓ it can mass assign data to the SmtcExternalKeyLookup model   0.25s
  ✓ it can update the SmtcExternalKeyLookup model record         0.35s

   PASS  Tests\Feature\ExampleTest
  ✓ it contains a successful example feature test                0.24s

  Tests:    6 passed (25 assertions)
  Duration: 3.84s

注意:下一版本将包含更多测试。