You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
558 lines
22 KiB
558 lines
22 KiB
<?php
|
|
|
|
namespace app\jobs\product;
|
|
|
|
use app\services\product\branch\StoreBranchProductAttrValueServices;
|
|
use app\services\product\branch\StoreBranchProductServices;
|
|
use app\services\product\product\StoreProductServices;
|
|
use app\services\product\sku\StoreProductAttrServices;
|
|
use app\services\product\sku\StoreProductAttrValueServices;
|
|
use app\services\store\SystemStoreServices;
|
|
use crmeb\basic\BaseJobs;
|
|
use crmeb\exceptions\AdminException;
|
|
use crmeb\services\erp\Erp as erpServices;
|
|
use crmeb\traits\QueueTrait;
|
|
use think\facade\Log;
|
|
|
|
class ProductSyncErp extends BaseJobs
|
|
{
|
|
use QueueTrait;
|
|
|
|
/**
|
|
* @return mixed
|
|
*/
|
|
public static function queueName()
|
|
{
|
|
return 'CRMEB_PRO_ERP';
|
|
}
|
|
|
|
/**
|
|
* 同步商品到erp
|
|
* @param $id
|
|
* @return mixed
|
|
*/
|
|
public function upProductToErp($id)
|
|
{
|
|
try {
|
|
/** @var StoreProductServices $productServices */
|
|
$productServices = app()->make(StoreProductServices::class);
|
|
// 获取商品信息
|
|
$productInfo = $productServices->getInfo($id)['productInfo'];
|
|
$data = [];
|
|
$attrs = $productInfo['attrs'] ?? [];
|
|
if (!$attrs && ($productInfo['attr'] ?? [])) {
|
|
$attrs = [$productInfo['attr']];
|
|
}
|
|
foreach ($attrs as $item) {
|
|
if ($item['pic'] && strstr($item['pic'], 'http') === false) {
|
|
$siteUrl = sys_config('site_url');
|
|
$item['pic'] = $siteUrl . $item['pic'];
|
|
}
|
|
|
|
$data[] = [
|
|
'i_id' => $productInfo['code'],
|
|
'sku_id' => $item['code'],
|
|
'name' => $productInfo['store_name'],
|
|
'properties_value' => str_replace(',', ' ', $item['values']),
|
|
's_price' => $item['price'],
|
|
'pic' => $item['pic'],
|
|
'c_price' => $item['cost'],
|
|
'market_price' => $item['ot_price'],
|
|
];
|
|
}
|
|
|
|
(new erpServices())->serviceDriver('product')->updateProduct($data);
|
|
} catch (\Exception $e) {
|
|
Log::error('商品上传失败, 原因: ' . $e->getMessage());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 上传店铺商品
|
|
* @param $id
|
|
* @param $shop
|
|
* @return bool
|
|
*/
|
|
public function upBranchProductToErp($id, $shop)
|
|
{
|
|
try {
|
|
/** @var StoreProductServices $productServices */
|
|
$productServices = app()->make(StoreProductServices::class);
|
|
// 获取商品信息
|
|
$productInfo = $productServices->getInfo($id)['productInfo'];
|
|
$data = [];
|
|
$attrs = $productInfo['attrs'] ?? [];
|
|
if (!$attrs && ($productInfo['attr'] ?? [])) {
|
|
$attrs = [$productInfo['attr']];
|
|
}
|
|
foreach ($attrs as $item) {
|
|
$data[] = [
|
|
'i_id' => $productInfo['code'],
|
|
'sku_id' => $item['code'],
|
|
'shop_i_id' => $shop['erp_shop_id'] . $productInfo['code'],
|
|
'shop_sku_id' => $shop['erp_shop_id'] . $item['code'],
|
|
'name' => $productInfo['store_name'],
|
|
'properties_value' => str_replace(',', ' ', $item['values']),
|
|
'shop_id' => $shop['erp_shop_id'],
|
|
];
|
|
}
|
|
|
|
(new erpServices())->serviceDriver('product')->updateShopProduct($data);
|
|
} catch (\Exception $e) {
|
|
Log::error('店铺商品上传失败, 原因: ' . $e->getMessage());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 添加商品同步到门店中
|
|
* @param $id
|
|
* @param $shop
|
|
*/
|
|
public function productToBranch($id, $shop)
|
|
{
|
|
/** @var StoreProductServices $productServices */
|
|
$productServices = app()->make(StoreProductServices::class);
|
|
// 获取商品信息
|
|
$productInfo = $productServices->getInfo($id)['productInfo'];
|
|
/** @var StoreProductAttrValueServices $storeProductAttrValueServices */
|
|
$storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
|
|
$skuArray = $storeProductAttrValueServices->getSkuArray(['product_id' => $id, 'type' => 0], 'unique', 'code');
|
|
$data = [
|
|
'product_id' => $id,
|
|
'image' => $productInfo['image'],
|
|
'store_name' => $productInfo['store_name'],
|
|
'store_info' => $productInfo['store_info'],
|
|
'keyword' => $productInfo['keyword'],
|
|
'bar_code' => $productInfo['bar_code'],
|
|
'cate_id' => $productInfo['cate_id'],
|
|
'store_id' => $shop['id'],
|
|
'sales' => 0,
|
|
'stock' => 0,
|
|
'sort' => 0,
|
|
'label_id' => $productInfo['label_id'],
|
|
'is_show' => 0,
|
|
'add_time' => time(),
|
|
'is_del' => 0,
|
|
'code' => $productInfo['code'],
|
|
];
|
|
$attrs = [];
|
|
foreach ($productInfo['attrs'] as $item) {
|
|
if (empty($item['code']) || !array_key_exists($item['code'], $skuArray)) {
|
|
continue;
|
|
}
|
|
$attrs[] = [
|
|
'product_id' => $id,
|
|
'store_id' => $shop['id'],
|
|
'unique' => $skuArray[$item['code']],
|
|
'sales' => 0,
|
|
'stock' => 0,
|
|
'type' => 0,
|
|
'bar_code' => $item['bar_code'],
|
|
'code' => $item['code'],
|
|
];
|
|
}
|
|
|
|
/** @var StoreBranchProductAttrValueServices $branchProductAttrServices */
|
|
$branchProductAttrServices = app()->make(StoreBranchProductAttrValueServices::class);
|
|
|
|
$branchProductAttrServices->transaction(function () use ($id, $data, $attrs, $shop, $branchProductAttrServices) {
|
|
|
|
/** @var StoreBranchProductServices $branchProductServices */
|
|
$branchProductServices = app()->make(StoreBranchProductServices::class);
|
|
|
|
// 判断门店是否有商品
|
|
$branchProduct = $branchProductServices->getOne(['product_id' => $id, 'store_id' => $shop['id']]);
|
|
if (empty($branchProduct)) {
|
|
$branchProductServices->save($data);
|
|
$branchProductAttrServices->saveAll($attrs);
|
|
} else {
|
|
$branchProductAttr = $branchProductAttrServices->getColumn(['product_id' => $id, 'store_id' => $shop['id']], '*', 'code');
|
|
if (!empty($branchProductAttr)) {
|
|
foreach ($attrs as $key => $attr) {
|
|
if (isset($branchProductAttr[$attr['code']])) {
|
|
unset($attrs[$key]);
|
|
}
|
|
}
|
|
if (!empty($attrs)) {
|
|
$branchProductAttrServices->saveAll($attrs);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 同步商品
|
|
* @param $spuArr
|
|
* @return bool
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function productFromErp($spuArr)
|
|
{
|
|
try {
|
|
$result = (new erpServices())->serviceDriver('product')->syncProduct([$spuArr]);;
|
|
$productList = $result['datas'];
|
|
$productInfo = [];
|
|
/** @var StoreProductServices $productServices */
|
|
$productServices = app()->make(StoreProductServices::class);
|
|
/** @var StoreProductAttrServices $productAttrServices */
|
|
$productAttrServices = app()->make(StoreProductAttrServices::class);
|
|
|
|
/** @var SystemStoreServices $systemStoreServices */
|
|
$systemStoreServices = app()->make(SystemStoreServices::class);
|
|
$systemStoreList = $systemStoreServices->getErpStore([['erp_shop_id', '>', 0]]);
|
|
foreach ($productList as $item) {
|
|
$productInfo = [
|
|
'image' => (string)$item['pic'],
|
|
'slider_image' => json_encode([(string)$item['pic']]),
|
|
'store_name' => $item['name'],
|
|
'store_info' => $item['name'],
|
|
'cate_id' => 0,
|
|
'price' => floatval($item['s_price']),
|
|
'ot_price' => floatval($item['market_price']),
|
|
'delivery_type' => '1,2,3',
|
|
'freight' => 1,
|
|
'is_show' => 0,
|
|
'add_time' => time(),
|
|
'cost' => floatval($item['c_price']),
|
|
'ficti' => 0,
|
|
'spec_type' => 1,
|
|
'code' => $item['i_id'],
|
|
];
|
|
$detail = $details = $value = [];
|
|
foreach ($item['skus'] as $items) {
|
|
$detail[] = $items['properties_value'];
|
|
$details[] = [
|
|
'name' => $items['properties_value'],
|
|
'select' => false
|
|
];
|
|
$value[] = [
|
|
'bar_code' => '',
|
|
'brokerage' => 0,
|
|
'brokerage_two' => 0,
|
|
'code' => $items['sku_id'],
|
|
'cost' => floatval($items['cost_price']),
|
|
'detail' => ['规格' => $items['properties_value']],
|
|
'ot_price' => floatval($items['market_price']),
|
|
'pic' => (string)$items['pic'],
|
|
'price' => floatval($items['sale_price']),
|
|
'select' => true,
|
|
'value1' => $items['properties_value'],
|
|
'values' => $items['properties_value'],
|
|
'vip_price' => 0,
|
|
'volume' => 0,
|
|
'weight' => 0,
|
|
'stock' => 0,
|
|
];
|
|
}
|
|
$pid = $productServices->value(['code' => $item['i_id']], 'id');
|
|
if (!$pid) {
|
|
$pid = $productServices->ErpProductSave($productInfo);
|
|
}
|
|
//检测库存警戒和检测是否售罄
|
|
ProductStockTips::dispatch([$pid, 0]);
|
|
|
|
$attr = [[
|
|
'value' => '规格',
|
|
'detail' => $detail,
|
|
'details' => $details,
|
|
]];
|
|
|
|
$skuList = $productAttrServices->validateProductAttr($attr, $value, $pid, 0, 0, 0);
|
|
$productAttrServices->saveProductAttr($skuList, $pid);
|
|
// 同步商品至erp门店
|
|
if (!empty($systemStoreList)) {
|
|
foreach ($systemStoreList as $store) {
|
|
ProductSyncErp::dispatchDo('productToBranch', [$pid, $store]);
|
|
}
|
|
}
|
|
}
|
|
|
|
//清除数据缓存
|
|
$productServices->cacheTag()->clear();
|
|
$productAttrServices->cacheTag()->clear();
|
|
|
|
} catch (\Exception $e) {
|
|
Log::error('商品同步失败, 原因: ' . $e->getMessage());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 同步商品库存
|
|
* @param array $ids
|
|
* @return bool
|
|
*/
|
|
public function stockFromErp(array $ids)
|
|
{
|
|
try {
|
|
/** @var StoreProductServices $storeProductServices */
|
|
$storeProductServices = app()->make(StoreProductServices::class);
|
|
|
|
/** @var StoreProductAttrValueServices $storeProductAttrValueServices */
|
|
$storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
|
|
|
|
//查询ids下的所有规格对应的sku
|
|
$list = $storeProductAttrValueServices->getSkuArray(['product_id' => $ids, 'type' => 0], 'code', 'id');
|
|
|
|
$values = array_filter(array_values($list));
|
|
if (empty($values)) {
|
|
throw new AdminException('没有符合同步库存的商品');
|
|
}
|
|
|
|
$skuData = $skuMap = [];
|
|
|
|
$basic = 20; // 单次查询数量最多20
|
|
$num = count($values);
|
|
$rate = ceil($num / $basic);
|
|
for ($i = 0; $i < $rate; $i++) {
|
|
$code = array_slice($values, $i * $basic, $basic);
|
|
$codeStr = implode(',', $code);
|
|
$result = (new erpServices())->serviceDriver('product')->syncStock($codeStr);
|
|
if (!empty($result['inventorys'])) {
|
|
foreach ($result['inventorys'] as $inventory) {
|
|
$skuMap[$inventory['sku_id']] = $inventory['qty'] - $inventory['order_lock'];
|
|
}
|
|
}
|
|
}
|
|
|
|
// 拼装规格数据
|
|
if (!empty($skuMap)) {
|
|
foreach ($skuMap as $key => $item) {
|
|
if ($id = array_search($key, $list)) {
|
|
$skuData[] = ['id' => $id, 'stock' => $item, 'sum_stock' => $item];
|
|
}
|
|
}
|
|
}
|
|
|
|
// 同步库存
|
|
$storeProductServices->transaction(function () use ($ids, $skuData, $storeProductAttrValueServices, $storeProductServices) {
|
|
// 同步规格库存
|
|
$storeProductAttrValueServices->saveAll($skuData);
|
|
// 同步商品库存
|
|
$productData = $storeProductAttrValueServices->getProductStockByValues($ids);
|
|
$storeProductServices->saveAll($productData);
|
|
});
|
|
|
|
/** @var SystemStoreServices $systemStoreServices */
|
|
$systemStoreServices = app()->make(SystemStoreServices::class);
|
|
$systemStoreList = $systemStoreServices->getErpStore([['erp_shop_id', '>', 0]]);
|
|
|
|
// 同步门店商品库存
|
|
if (!empty($systemStoreList)) {
|
|
foreach ($systemStoreList as $store) {
|
|
ProductSyncErp::dispatchDo('syncBranchProductStock', [$ids[0], $skuMap, $store['id']]);
|
|
}
|
|
}
|
|
|
|
//清除缓存
|
|
$storeProductServices->cacheTag()->clear();
|
|
/** @var StoreProductAttrServices $attrService */
|
|
$attrService = app()->make(StoreProductAttrServices::class);
|
|
$attrService->cacheTag()->clear();
|
|
} catch (\Exception $e) {
|
|
Log::error('库存获取失败, 原因: ' . $e->getMessage());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 同步门店商品库存
|
|
* @param int $productId
|
|
* @param array $data
|
|
* @param int $storeId
|
|
*/
|
|
public function syncBranchProductStock(int $productId, array $data, int $storeId)
|
|
{
|
|
/** @var StoreBranchProductAttrValueServices $branchProductAttrServices */
|
|
$branchProductAttrServices = app()->make(StoreBranchProductAttrValueServices::class);
|
|
$branchProductAttrServices->transaction(function () use ($productId, $storeId, $data, $branchProductAttrServices) {
|
|
$list = $branchProductAttrServices->getColumn(['store_id' => $storeId, 'product_id' => $productId, 'code' => array_keys($data)], '*', 'id');
|
|
if (!empty($list)) {
|
|
foreach ($list as $item) {
|
|
$branchProductAttrServices->update($item['id'], ['stock' => $data[$item['code']]]);
|
|
}
|
|
}
|
|
|
|
$stock = (int)$branchProductAttrServices->sum(['product_id' => $productId, 'store_id' => $storeId], 'stock');
|
|
|
|
/** @var StoreBranchProductServices $branchProductServices */
|
|
$branchProductServices = app()->make(StoreBranchProductServices::class);
|
|
$branchProductId = $branchProductServices->value(['product_id' => $productId, 'store_id' => $storeId], 'id');
|
|
if ($branchProductId > 0) {
|
|
$branchProductServices->update($branchProductId, ['stock' => $stock]);
|
|
}
|
|
});
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 同步商品至新增门店
|
|
* @param int $shopId
|
|
*/
|
|
public function syncProductToBranch(int $shopId)
|
|
{
|
|
/** @var StoreProductServices $productServices */
|
|
$productServices = app()->make(StoreProductServices::class);
|
|
$list = $productServices->getColumn(['is_del' => 0, 'is_show' => 1], 'id', 'id');
|
|
|
|
if (!empty($list)) {
|
|
foreach ($list as $item) {
|
|
ProductSyncErp::dispatchDo('productToBranch', [$item, ['id' => $shopId]]);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 更新商品库存
|
|
* @param array $list
|
|
* @return bool
|
|
*/
|
|
public function updatePlatformStock(array $list): bool
|
|
{
|
|
try {
|
|
/** @var StoreProductAttrValueServices $storeProductAttrValueServices */
|
|
$storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
|
|
|
|
$data = array_column($list, 'qty', 'sku_id');
|
|
$shopData = array_keys(array_column($list, 'shop_id', 'shop_id'));
|
|
$erpShopId = $shopData[0] ?? 0;
|
|
if ($erpShopId < 1) {
|
|
return true;
|
|
}
|
|
|
|
// 更新平台商品库存
|
|
$defaultShopId = (int)sys_config('jst_default_shopid');
|
|
if ($defaultShopId == $erpShopId) {
|
|
$this->updateStoreProductValueStock($data);
|
|
}
|
|
|
|
$attrs = $storeProductAttrValueServices->getColumn(['code' => array_keys($data)], 'id, product_id, suk, stock, sum_stock', 'code');
|
|
$productIds = array_unique(array_column($attrs, 'product_id'));
|
|
|
|
/** @var SystemStoreServices $systemStoreServices */
|
|
$systemStoreServices = app()->make(SystemStoreServices::class);
|
|
$systemStoreList = $systemStoreServices->getErpStore([['erp_shop_id', '=', $erpShopId]]);
|
|
|
|
// 同步门店商品规格库存
|
|
foreach ($systemStoreList as $store) {
|
|
ProductSyncErp::dispatchDo('updateStoreAttrStockByCode', [$data, $store['id']]);
|
|
}
|
|
|
|
// 同步门店商品库存
|
|
foreach ($systemStoreList as $store) {
|
|
ProductSyncErp::dispatchDo('updateStoreProductStock', [$productIds, $store['id']]);
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::error('更新门店库存失败, 原因: ' . $e->getMessage());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 更新门店规格库存
|
|
* @param array $data
|
|
* @param int $storeId
|
|
* @return bool
|
|
*/
|
|
public function updateStoreAttrStockByCode(array $data, int $storeId): bool
|
|
{
|
|
try {
|
|
/** @var StoreBranchProductAttrValueServices $branchProductAttrServices */
|
|
$branchProductAttrServices = app()->make(StoreBranchProductAttrValueServices::class);
|
|
$list = $branchProductAttrServices->getColumn(['store_id' => $storeId, 'code' => array_keys($data)], 'code', 'id');
|
|
$skuData = [];
|
|
|
|
// 同步规格库存
|
|
foreach ($data as $key => $item) {
|
|
if ($id = array_search($key, $list)) {
|
|
$skuData[] = ['id' => $id, 'stock' => $item];
|
|
}
|
|
}
|
|
// 同步规格库存
|
|
$branchProductAttrServices->saveAll($skuData);
|
|
} catch (\Exception $e) {
|
|
Log::error('门店: ' . $storeId . ' 规格库存更新失败, 原因: ' . $e->getMessage());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 更新门店商品库存
|
|
* @param array $productIds
|
|
* @param int $storeId
|
|
* @return bool
|
|
*/
|
|
public function updateStoreProductStock(array $productIds, int $storeId): bool
|
|
{
|
|
try {
|
|
/** @var StoreBranchProductAttrValueServices $branchProductAttrServices */
|
|
$branchProductAttrServices = app()->make(StoreBranchProductAttrValueServices::class);
|
|
|
|
/** @var StoreBranchProductServices $branchProductServices */
|
|
$branchProductServices = app()->make(StoreBranchProductServices::class);
|
|
|
|
$productData = $branchProductAttrServices->getProductStockByValues($productIds, $storeId);
|
|
foreach ($productData as $product) {
|
|
$branchProductServices->update(['product_id' => $product['product_id'], 'store_id' => $storeId], ['stock' => $product['stock']]);
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::error('门店: ' . $storeId . ' 商品库存更新失败, 原因: ' . $e->getMessage());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 更新平台商品库存
|
|
* @param array $data
|
|
* @return bool
|
|
*/
|
|
public function updateStoreProductValueStock(array $data): bool
|
|
{
|
|
try {
|
|
/** @var StoreProductServices $storeProductServices */
|
|
$storeProductServices = app()->make(StoreProductServices::class);
|
|
|
|
/** @var StoreProductAttrValueServices $storeProductAttrValueServices */
|
|
$storeProductAttrValueServices = app()->make(StoreProductAttrValueServices::class);
|
|
|
|
$skuList = $storeProductAttrValueServices->getSkuArray(['code' => array_keys($data), 'type' => 0], 'id, product_id,code', 'id');
|
|
if (empty($skuList)) {
|
|
throw new AdminException('没有符合同步库存的商品');
|
|
}
|
|
|
|
$ids = array_unique(array_column($skuList, 'product_id'));
|
|
|
|
$skuData = [];
|
|
foreach ($skuList as $key => $sku) {
|
|
if (array_key_exists($sku['code'], $data)) {
|
|
$skuData[] = ['id' => $key, 'stock' => $data[$sku['code']]];
|
|
}
|
|
}
|
|
|
|
if (empty($skuData)) {
|
|
return true;
|
|
}
|
|
|
|
// 同步库存
|
|
$storeProductServices->transaction(function () use ($ids, $skuData, $storeProductAttrValueServices, $storeProductServices) {
|
|
// 同步规格库存
|
|
$storeProductAttrValueServices->saveAll($skuData);
|
|
// 同步商品库存
|
|
$productData = $storeProductAttrValueServices->getProductStockByValues($ids);
|
|
$storeProductServices->saveAll($productData);
|
|
});
|
|
} catch (\Exception $e) {
|
|
Log::error('平台商品库存更新失败, 原因: ' . $e->getMessage());
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|