承接 modulabs/laravel-google-merchant 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

modulabs/laravel-google-merchant

Composer 安装命令:

composer require modulabs/laravel-google-merchant

包简介

Laravel Google Merchant Products API for Google Shopping.

README 文档

README

A sweet package for managing Google Merchant Center feeds for Google Shopping. This package is prepared to implement the advanced Content API for Merchants.

Example usage:

use GUILLMZ\GoogleMerchantApi\Facades\ProductApi;
use GUILLMZ\GoogleMerchantApi\Facades\OrderApi;

...

ProductApi::insert(function($product){
    $product->offerId(1)
        	->title('Purple Shoes')
        	->description('What are thooose!!')
        	->price(10)
        	->custom('purchase_quantity_limit', 1000)
            ->availabilityDate( today()->addDays(7) );
})->then(function($response){
    echo 'Product inserted';
})->otherwise(function($response){
    echo 'Insert failed';
})->catch(function($e){
    echo($e->getResponse()->getBody()->getContents());
});

OrderApi::list()->then(function($response){
    //
})->otherwise(function($response){
    echo 'List failed';
})->catch(function($e){
    echo($e->getResponse()->getBody()->getContents());
});


OrderApi::scout(); // Scout and fire event

Features

  • Products API
    • Implements the insert, get, delete and list API calls
    • Uses defined schema interface for directly working with eloquent models (a product model)
    • Event listeners to respond to changes made to eloquent models, and insert them automatically
  • Orders API
    • Implements the acknowledge, cancel, cancelLineItem, rejectReturnLineItem, returnRefundLineItem, get and list API calls.
    • Internal schedule scouts un-acknowledged orders and fires an event. This means new orders on your Google Shopping can be automatically acknowledged and registered.
    • Includes sandbox functions for testOrders.
  • Multiple Merchants (1.1.0)

Updating to 1.1.x

Although backwards compatible, be sure to update your config to be able to use multiple merchants.

Installation

Via composer:

composer require modulabs/laravel-google-merchant

Install the service provider (skip for Laravel>=5.5);

// config/app.php
'providers' => [
    ...
    GUILLMZ\GoogleMerchantApi\GoogleMerchantApiServiceProvider::class,
],

Publish the config

php artisan vendor:publish --tag="google-merchant-api-config"

Setup & Authorisation

  • Follow the instructions here and create a service account key. Create storage/app/google-merchant-api/service-account-credentials.json in your app root and store the downloaded json contents
  • Obtain your numeric Merchant ID
  • Add your Merchant ID and the path to your service account credentials to the config
  • In the config, setup the attributes section in product content if you need to use arrays or models

Usage

Multiple Merchants

From 1.1.0 we can now define multiple merchants and switch between them by simply calling the merchant method from either the Order or Product API class.

ProductApi::merchant('my-pet-store')->insert($product);
// config/laravel-google-merchant-api.php
...
    'merchants' => [
        'my-pet-store' => [
			'app_name' => config('app.name'),
			'merchant_id' => '000000000',
			'client_credentials_path' => storage_path('app/my-pet-store-credentials.json'),
		]
    ],
...

Or

ProductApi::merchant([
    'app_name' => 'My Pet Store',
    'merchant_id' => '000000000',
    'client_credentials_path' => storage_path('app/my-pet-store-credentials.json')
])->insert($product);

Product API

The Google Merchant contents can be queried via the insert, get, delete, and list methods. The product content is contained and handled via the Product class. An instance of this class can be passed directly or resolved in a Closure callback. An instance can be population by

  • Directly accessing underlying attributes. See special functions.
  • Passing an eloquent model, or by
  • Passing a raw array

To pass an array or a model, the attributes relationships must be defined in the config.

Insert

The insert method creates a new content, as well as updates an old content if the channel, contentLanguage, targetCountry and offerId are the same.

$attributes = [
    'id' => 1, // maps to offerId (if set in config)
    'name' => 'Product 1', // likewise maps to title
];
ProductApi::insert(function($product) use($attributes){
    $product->with($attributes)
        	->link('https://moirei.com/mg001')
        	->price(60, 'USD');
})->then(function($data){
    echo 'Product inserted';
})->otherwise(function(){
    echo 'Insert failed';
})->catch(function($e){
    dump($e);
});

With arrays:

use GUILLMZ\GoogleMerchantApi\Contents\Product\Product as GMProduct;

...
$attributes = [
    'id' => 1,
    'name' => 'Product 1',
];
$product = (new GMProduct)->with($attributes);

The attributes values must be defined as per the attributes map in the config.

With Eloquent Models:

use App\Models\Product;
use GUILLMZ\GoogleMerchantApi\Contents\Product\Product as GMProduct;


...
$model = Product::find(1);
$product = (new GMProduct)->with($model);

ProductApi::insert($product)->catch(function($e){
    // always catch exceptions
});

The model attributes values must be defined as per the attributes map in the config. For accessing undefined models attributes, use Accessors and custom Model attributes:

protected $appends = [
    'availability',
    'gm_price',
];

...

public function getAvailabilityAttribute(){
    return 'in stock'; // calculate
}
public function getGmPriceAttribute(){
    return [
        'value' => $this->price,
        'currency' => $this->currency->code,
    ];
}

For setting custom Product contents (customAttributes), you're probably better off using the custom() method. Likewise for availabilityDate use the availabilityUntil() method.

With Events & Listeners:

The provided event and listener can be setup such that when your application creates or updates a model, the product content is automatically inserted.

To set this up, add the following snippet to your eloquent mode. The product variable can be a model or an array.

use GUILLMZ\GoogleMerchantApi\Events\ProductCreatedOrUpdatedEvent;

...

/**
 * The "booting" method of the model.
 *
 * @return void
 */
protected static function boot() {
    parent::boot();

    // when a product is created
    static::created(function(Product $product){
        // perhaps a logic to ignore drafts and private products
        if($product->is_active && (config('app.env') === 'production')){
        	event(new ProductCreatedOrUpdatedEvent($product));
        }
    });

    // when a product is updated
    static::updated(function(Product $product){
        // perhaps a logic to ignore drafts and private products
        if($product->is_active && (config('app.env') === 'production')){
        	event(new ProductCreatedOrUpdatedEvent(function($gm_product) use ($product){
                $gm_product->with($product)
                    	   ->preorder()
                    	   ->availabilityDate($product->preorder_date);
            }));
        }
    });
}

Next, define the events relationship in EventServiceProvider.php.

use GUILLMZ\GoogleMerchantApi\Listeners\ProductCreatedOrUpdatedListener;

...

/**
 * The event listener mappings for the application.
 *
 * @var array
 */
protected $listen = [
    ...,
    /**
     * Product events
     */
    ProductCreatedOrUpdatedEvent::class => [
        ProductCreatedOrUpdatedListener::class,
    ],

];

Get & List

ProductApi::get($product)->then(function($data){
    //
})->catch(function($e){
    // always catch exceptions
});

The list method calls the get method without any parameters;

ProductApi::list()->then(function($data){
    //
});

So the following should likewise retrieve the product list:

ProductApi::get()->then(function($data){
    //
});

Delete

ProductApi::delete($product)->then(function($data){
    //
});

To set up with the event listener, add the following to your eloquent model:

use GUILLMZ\GoogleMerchantApi\Events\ProductDeletedEvent;

...

protected static function boot() {
    parent::boot();

    ...

    // when a product is deleted
    static::deleted(function(Product $product){
        if(config('app.env') === 'production'){
        	event(new ProductDeletedEvent($product));
        }
    });
}

Then define the relationship in EventServiceProvider.php:

use GUILLMZ\GoogleMerchantApi\Listeners\ProductDeletedListener;

...

protected $listen = [
    ...,
    ProductDeletedEvent::class => [
        ProductDeletedListener::class,
    ],
];

Order API

Please note that these implementations have not been properly tested.

Using the API methods

The acknowledge, cancel, cancelLineItem, rejectReturnLineItem, returnRefundLineItem, get, list methods are currently implemented for interacting with your Google Merchant.

The format for using these methods are standard across the entire package. For example, an order can be acknowledged by

OrderApi::acknowledge(function($order){
    $order->id('TEST-1953-43-0514');
});

or by

$order = (new Order)->with([
    'id' => 'TEST-1953-43-0514',
]);
OrderApi::acknowledge($order);

Additionally the listAcknowledged method is provided so one can list acknowledged orders if needed.

Scheduled Scouts

If schedule_orders_check is set as true in the config, the package will regularly scout un-acknowledged orders and will fire a \GUILLMZ\GoogleMerchantApi\Events\NewOrdersScoutedEvent event. This event includes an array of orders of class \GUILLMZ\GoogleMerchantApi\Contents\Order. The orders are structured as per the Order Resource.

Example handle in your listener:

use GUILLMZ\GoogleMerchantApi\Events\NewOrdersScoutedEvent;
use GUILLMZ\GoogleMerchantApi\Facades\OrderApi;

...
public function handle(NewOrdersScoutedEvent $event)
{
    $merchant = $event->merchant; // array key as defined in config
    $merchant_id = $event->merchant_id;

    foreach($event->orders as $gm_order){
        OrderApi::acknowledge($gm_order);

        $gm_order = $gm_order->all(); // get all attributes, including mutated attributes
        foreach($gm_order['lineItems'] as $line_item){
            $model = $line_item['model']; // retrieves model
            $quantity = $line_item['quantityOrdered'];
            $shipping = $line_item['shippingDetails'];
            $delivery_date = $shipping['deliverByDate']->diffForHumans();

            // register new order item
        }

        // register new order
    }
}

Notes:

  • Accessing the lineItems will automatically resolve and attach the corresponding model to each item. Of course this assumes your inserted products' offerId correspond to the model's ID & primary key.
  • If you haven't already started Laravel scheduler, you'll need to add the following Cron entry to your server. * * * * * php artisan schedule:run >> /dev/null 2>&1.
  • It's important you test that the scheduler is set up correctly. For this reason, the GUILLMZ\GoogleMerchantApi\Events\OrderContentScoutedEvent event is provided. If debug_scout is set to true in the config, this event is fired whenever the scheduler fires.

Sandboxing

The OrderApi class provide a way of calling some of the sandbox operations. Example:

OrderApi::sandbox()->create(function($order){
    $order->shippingCost(30)
          ->shippingOption('economy')
          ->predefinedEmail('pog.dwight.schrute@gmail.com')
          ->predefinedDeliveryAddress('dwight');
})

You may use

OrderApi::sandbox()->testCreate();

to use a preset example.

Implemented sandbox actions:

Function Sandbox Action
create createtestorder
advance advancetestorder
cancel createtestorder
createReturn createtestreturn

Commands

This package provides an artisan command for scouting orders.

php artisan gm-orders:scout

Handling Errors

Methods that throw exceptions

  • GUILLMZ\GoogleMerchantApi\Contents\Product::with()

    throws GUILLMZ\GoogleMerchantApi\Exceptions\ProductContentAttributesUndefined if the supplied attributes is not a Model or array.

  • The insert, get, delete, list, listAcknowledged and scout methods in the API classes will throw GuzzleHttp\Exception\ClientException if the client request is corrupted, fails, not defined or not authorised.

  • The GUILLMZ\GoogleMerchantApi\Exceptions\Invalid**Input exceptions are thrown if an unresolvable entity is passed as a content attribute.

  • The merchant method throws GUILLMZ\GoogleMerchantApi\Exceptions\InvalidMechantDetails if unable to resolve a merchant ID or credentials path.

Exceptions should be handled using the catch function. If making synchronous calls, use the try-catch block. You'd be well advised to always catch requests (and notify your business logic), seeing that Google has a million reasons to deny any request.

Design Notes

  • Insert, List, Get, Delete methods will always return a clone of the original instance if using the default asynchronous feature. This allows the then, otherwise, and catch callbacks of multiple requests to not override. These methods return a Guzzle response if set to synchronous mode.
  • If the delete method is called and the resolved content ID is invalid, it returns without making any requests or throwing any errors. If the get method, it returns a list of products or orders.
  • A valid product content ID follows the pattern online:en:AU:1 i.e. channel:contentLanguage:targetCountry:offerId. This ID is of course auto generated; and the attributes, except for offerId, have default values.
  • Requests can take up to 2 hours before they reflect on your Google Merchant Center. Patience!
  • Unlike the ProductApi or OrderApi classes, the events constructor may take a Model, array or callback.
  • Calling the all method on a Product, Order or any content class will resolve all mutated attributes. e.g. $order['lineItems'][0]['shippingDetails']['deliverByDate'] returns a Carbon.

Synchronous Calls

All the above are by default asynchronous. To make synchronous calls, use the sync method:

try{
    $response = ProductApi::sync()->insert(function($product){
        $product->offerId(1)
            	->country('AU')
            	->inStock(false);
    });
}catch(\GuzzleHttp\Exception\ClientException $e){
    //
}

Note: In this case, methods such as insert, get, delete, and list, etc, returns a Guzzle response when called asynchronously (rather than an instance of ProductApi or OrderApi. This means your exception blocks should be wrapped around requests.

Contributing

This package is intended to provide a Laravel solution for the Google Shopping API for Google Merchant. Currently, only the Product Content has been adequately implemented and tested. For orders, refunds, etc., ideas and pull-requests are welcome.

Credits

License

The MIT License (MIT). Please see License File for more information.

modulabs/laravel-google-merchant 适用场景与选型建议

modulabs/laravel-google-merchant 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 6 次下载、GitHub Stars 达 0, 最近一次更新时间为 2024 年 04 月 22 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「laravel」 「Google Merchant API」 「Google Shopping API」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 modulabs/laravel-google-merchant 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 modulabs/laravel-google-merchant 我们能提供哪些服务?
定制开发 / 二次开发

基于 modulabs/laravel-google-merchant 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 6
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 5
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2024-04-22