Explorar o código

refactor(command): 重构1688商品导入命令的原价和分润更新逻辑

- 引入 ProductRepository 依赖进行统一的数据更新操作
- 新增 updateProductData 方法封装完整的商品数据组装和更新流程
- 将原有的直接数据库操作改为通过仓库模式进行更新
- 移除硬编码的分润设置逻辑,统一在仓库层处理
- 更新控制台输出信息,反映新的更新状态
- 优化注释文档,明确方法职责和参数说明
- 调整价格阶梯计算逻辑,确保原价和分润设置准确无误
shichen hai 2 meses
pai
achega
d9f99d4ed4
Modificáronse 1 ficheiros con 174 adicións e 78 borrados
  1. 174 78
      app/command/AlibabaTodayImport.php

+ 174 - 78
app/command/AlibabaTodayImport.php

@@ -2,6 +2,7 @@
2 2
 
3 3
 namespace app\command;
4 4
 
5
+use app\common\repositories\store\product\ProductRepository;
5 6
 use app\services\ThirdParty\AlibabaAgent\ProductService;
6 7
 use think\console\Command;
7 8
 use think\console\Input;
@@ -12,7 +13,8 @@ use think\facade\Db;
12 13
  * 今日1688商品自动入库命令
13 14
  *
14 15
  * 从 alibaba_import_goods 表中获取今日创建的商品,
15
- * 调用 ProductService::importToStoreProduct() 进行正式入库到 store_product 表
16
+ * 调用 ProductService::importToStoreProduct() 进行正式入库到 store_product 表,
17
+ * 然后通过 ProductRepository::update() 更新原价和分润设置
16 18
  *
17 19
  * 用法:
18 20
  *   php think alibaba:today-import                                          # 默认今天,mer_id=3447
@@ -29,7 +31,6 @@ use think\facade\Db;
29 31
  *   - extension_type: 1(开启分润)
30 32
  *   - concession_pri: 售价 × 15%(商家让利金额)
31 33
  *   - extension_one: 15(SKU级分润比例)
32
- *   - plate_mer_profit: 0(平台商户利润)
33 34
  *   - commission: 保持原样(不修改)
34 35
  *
35 36
  * 原价计算规则(根据SKU售价阶梯加价):
@@ -37,7 +38,7 @@ use think\facade\Db;
37 38
  *   21-50元   => 固定加20元
38 39
  *   51-120元  => 固定加40元
39 40
  *   121-200元 => 固定加45元
40
- *   201-300元 => 固定加50元
41
+ *   201元以上 => 固定加50元
41 42
  */
42 43
 class AlibabaTodayImport extends Command
43 44
 {
@@ -153,81 +154,13 @@ class AlibabaTodayImport extends Command
153 154
                         $productId = $result['product_id'];
154 155
                         $globalSuccess++;
155 156
 
156
-                        // 4b. 根据SKU售价阶梯计算原价(ot_price)
157
+                        // 4b. 组装数据,调用 ProductRepository::update() 更新原价和分润
157 158
                         try {
158
-                            // 获取所有SKU的售价(用 unique 字段唯一标识每个SKU)
159
-                            $skuValues = Db::name('store_product_attr_value')
160
-                                ->where('product_id', $productId)
161
-                                ->field('unique, price')
162
-                                ->select()
163
-                                ->toArray();
164
-
165
-                            $skuPrices = [];
166
-                            $skuOtPrices = [];
167
-                            foreach ($skuValues as $sku) {
168
-                                $salePrice = (float)$sku['price'];
169
-                                $skuPrices[] = $salePrice;
170
-
171
-                                // 根据售价区间计算原价
172
-                                $otPrice = self::calcOtPrice($salePrice);
173
-                                $skuOtPrices[] = $otPrice;
174
-
175
-                                // 通过 unique 字段更新当前SKU的 ot_price
176
-                                Db::name('store_product_attr_value')
177
-                                    ->where('unique', $sku['unique'])
178
-                                    ->update(['ot_price' => $otPrice]);
179
-                            }
180
-
181
-                            // 更新 store_product 表的 price(最低售价)和 ot_price(最高原价)
182
-                            $minPrice = !empty($skuPrices) ? min($skuPrices) : 0;
183
-                            $maxOtPrice = !empty($skuOtPrices) ? max($skuOtPrices) : 0;
184
-                            Db::name('store_product')
185
-                                ->where('product_id', $productId)
186
-                                ->update([
187
-                                    'price'    => $minPrice,
188
-                                    'ot_price' => $maxOtPrice,
189
-                                ]);
190
-
191
-                            $output->write("<info>[原价已计算]</info> ");
192
-                        } catch (\Throwable $priceE) {
193
-                            $output->write("<comment>[原价计算失败: {$priceE->getMessage()}]</comment> ");
194
-                        }
195
-
196
-                        // 4c. 设置分润(写死15%)
197
-                        try {
198
-                            // 获取商品最低售价
199
-                            $storeProduct = Db::name('store_product')
200
-                                ->where('product_id', $productId)
201
-                                ->field('price')
202
-                                ->find();
203
-
204
-                            $salePrice = $storeProduct ? (float)$storeProduct['price'] : 0;
205
-
206
-                            // 计算 concession_pri = 售价 × 15%,使用 bc 函数保留两位小数
207
-                            $concessionPri = '0.00';
208
-                            if ($salePrice > 0) {
209
-                                $concessionPri = bcmul((string)$salePrice, (string)$profitConfig['concession_rate'], 2);
210
-                            }
211
-
212
-                            // 更新 store_product 表的分润字段(commission保持原样不修改)
213
-                            Db::name('store_product')
214
-                                ->where('product_id', $productId)
215
-                                ->update([
216
-                                    'extension_type' => $profitConfig['extension_type'],
217
-                                    'concession_pri' => $concessionPri,
218
-                                ]);
219
-
220
-                            // 更新 store_product_attr_value 表的 SKU 分润比例
221
-                            Db::name('store_product_attr_value')
222
-                                ->where('product_id', $productId)
223
-                                ->update([
224
-                                    'extension_one' => $profitConfig['extension_one'],
225
-                                ]);
226
-
159
+                            self::updateProductData($productId, $merId, $profitConfig);
227 160
                             $globalProfitSet++;
228
-                            $output->write("<info>[分润15%已设置]</info> ");
229
-                        } catch (\Throwable $profitE) {
230
-                            $output->write("<comment>[分润设置失败: {$profitE->getMessage()}]</comment> ");
161
+                            $output->write("<info>[原价+分润已更新]</info> ");
162
+                        } catch (\Throwable $updateE) {
163
+                            $output->write("<comment>[更新失败: {$updateE->getMessage()}]</comment> ");
231 164
                         }
232 165
 
233 166
                         $output->writeln("<info>成功 => product_id={$productId}</info>");
@@ -246,7 +179,7 @@ class AlibabaTodayImport extends Command
246 179
             // 每批结束后输出当前进度和耗时
247 180
             $batchElapsed = time() - $batchStartTime;
248 181
             $totalElapsed = time() - $startTime;
249
-            $output->writeln("  本批耗时: {$batchElapsed}s | 累计耗时: {$totalElapsed}s | 累计成功: {$globalSuccess} | 累计失败: {$globalFail} | 分润设置: {$globalProfitSet}");
182
+            $output->writeln("  本批耗时: {$batchElapsed}s | 累计耗时: {$totalElapsed}s | 累计成功: {$globalSuccess} | 累计失败: {$globalFail} | 更新: {$globalProfitSet}");
250 183
             $output->writeln('');
251 184
 
252 185
             // 每批之间短暂休眠,避免数据库压力过大
@@ -266,7 +199,7 @@ class AlibabaTodayImport extends Command
266 199
         $output->writeln("总处理:         {$total} 条");
267 200
         $output->writeln("成功:           {$globalSuccess} 条");
268 201
         $output->writeln("失败:           {$globalFail} 条");
269
-        $output->writeln("已设置分润15%:  {$globalProfitSet} 条");
202
+        $output->writeln("已更新原价+分润: {$globalProfitSet} 条");
270 203
 
271 204
         if ($globalFail > 0) {
272 205
             $output->writeln('');
@@ -280,6 +213,169 @@ class AlibabaTodayImport extends Command
280 213
     }
281 214
 
282 215
     /**
216
+     * 组装数据并调用 ProductRepository::update() 更新商品
217
+     *
218
+     * 从数据库查询商品完整信息,组装成 update 接口所需的格式,
219
+     * 修改 ot_price(按阶梯计算)和 extension_one(15),
220
+     * 然后调用 ProductRepository::update() 执行更新。
221
+     *
222
+     * @param int   $productId
223
+     * @param int   $merId
224
+     * @param array $profitConfig
225
+     * @throws \Throwable
226
+     */
227
+    protected static function updateProductData(int $productId, int $merId, array $profitConfig): void
228
+    {
229
+        // 1. 查询 store_product 表获取商品基本信息
230
+        $product = Db::name('store_product')
231
+            ->where('product_id', $productId)
232
+            ->find();
233
+
234
+        if (!$product) {
235
+            throw new \RuntimeException("商品不存在 product_id={$productId}");
236
+        }
237
+
238
+        // 2. 查询 store_product_attr_value 表获取所有SKU
239
+        $skuValues = Db::name('store_product_attr_value')
240
+            ->where('product_id', $productId)
241
+            ->select()
242
+            ->toArray();
243
+
244
+        if (empty($skuValues)) {
245
+            throw new \RuntimeException("商品SKU数据为空 product_id={$productId}");
246
+        }
247
+
248
+        // 3. 查询 store_product_attr 表获取规格属性
249
+        $attrList = Db::name('store_product_attr')
250
+            ->where('product_id', $productId)
251
+            ->select()
252
+            ->toArray();
253
+
254
+        // 4. 查询 store_product_content 表获取商品详情
255
+        $content = Db::name('store_product_content')
256
+            ->where('product_id', $productId)
257
+            ->value('content');
258
+
259
+        // 5. 组装 attrValue 数据(参考 detail 接口返回格式)
260
+        $attrValue = [];
261
+        $skuPrices = [];
262
+        foreach ($skuValues as $sku) {
263
+            $salePrice = (float)$sku['price'];
264
+            $skuPrices[] = $salePrice;
265
+
266
+            // 根据售价区间计算原价
267
+            $otPrice = self::calcOtPrice($salePrice);
268
+
269
+            // detail 字段(规格明细)
270
+            $detail = [];
271
+            if (!empty($sku['detail'])) {
272
+                $detail = is_string($sku['detail']) ? json_decode($sku['detail'], true) : $sku['detail'];
273
+            }
274
+
275
+            $attrValue[] = [
276
+                'product_id'       => $productId,
277
+                'detail'           => $detail,
278
+                'sku'              => $sku['sku'] ?? '',
279
+                'stock'            => $sku['stock'] ?? 0,
280
+                'sales'            => $sku['sales'] ?? 0,
281
+                'image'            => $sku['image'] ?? '',
282
+                'bar_code'         => $sku['bar_code'] ?? '',
283
+                'cost'             => (string)($sku['cost'] ?? 0),
284
+                'ot_price'         => (string)$otPrice,
285
+                'price'            => (string)($sku['price'] ?? 0),
286
+                'volume'           => (string)($sku['volume'] ?? 0),
287
+                'weight'           => (string)($sku['weight'] ?? 0),
288
+                'type'             => $sku['type'] ?? 0,
289
+                'extension_one'    => (string)$profitConfig['extension_one'],
290
+                'extension_two'    => $sku['extension_two'] ?? null,
291
+                'unique'           => $sku['unique'] ?? '',
292
+                'dacang_price'     => (string)($sku['dacang_price'] ?? 0),
293
+                'cost_price'       => $sku['cost_price'] ?? null,
294
+                'gong_sku_id'      => $sku['gong_sku_id'] ?? null,
295
+                'gong_mer_profit'  => (string)($sku['gong_mer_profit'] ?? 0),
296
+                'gong_pension'     => $sku['gong_pension'] ?? null,
297
+                'gong_market_price'=> (string)($sku['gong_market_price'] ?? 0),
298
+                'plate_mer_profit' => (string)($sku['plate_mer_profit'] ?? 0),
299
+                'pension_num'      => (string)($sku['pension_num'] ?? 0),
300
+                'share_num'        => (string)($sku['share_num'] ?? 0),
301
+                'stock_num'        => (string)($sku['stock_num'] ?? 0),
302
+                'shares_num'       => (string)($sku['shares_num'] ?? 0),
303
+                'is_usable'        => $sku['is_usable'] ?? 0,
304
+                'sku_id'           => $sku['sku_id'] ?? '',
305
+                'spec_id'          => $sku['spec_id'] ?? '',
306
+                'value0'           => $sku['value0'] ?? ($sku['sku'] ?? ''),
307
+                'dacang_cost_price'=> (string)($sku['dacang_cost_price'] ?? 0),
308
+                'no_dacang_cost_price'=> (string)($sku['no_dacang_cost_price'] ?? 0),
309
+            ];
310
+        }
311
+
312
+        // 6. 组装 attr 数据(规格属性)
313
+        $attr = [];
314
+        foreach ($attrList as $attrItem) {
315
+            $detail = !empty($attrItem['attr_values'])
316
+                ? explode('-!-', $attrItem['attr_values'])
317
+                : [];
318
+            $attr[] = [
319
+                'value'  => $attrItem['attr_name'],
320
+                'detail' => $detail,
321
+            ];
322
+        }
323
+
324
+        // 7. 计算商品级价格
325
+        $minPrice = !empty($skuPrices) ? min($skuPrices) : 0;
326
+        $maxOtPrice = self::calcOtPrice($minPrice);
327
+        // 取所有SKU中最大的ot_price
328
+        foreach ($skuPrices as $p) {
329
+            $ot = self::calcOtPrice($p);
330
+            if ($ot > $maxOtPrice) {
331
+                $maxOtPrice = $ot;
332
+            }
333
+        }
334
+
335
+        // 8. 组装完整数据(参考 detail 接口返回 + update 接口所需字段)
336
+        $sliderImages = !empty($product['slider_image'])
337
+            ? (is_string($product['slider_image']) ? explode(',', $product['slider_image']) : $product['slider_image'])
338
+            : [];
339
+
340
+        $updateData = [
341
+            'volunteer'       => $product['volunteer'] ?? 0,
342
+            'image'           => $product['image'] ?? '',
343
+            'slider_image'    => $sliderImages,
344
+            'store_name'      => $product['store_name'] ?? '',
345
+            'store_info'      => $product['store_info'] ?? '',
346
+            'keyword'         => $product['keyword'] ?? '',
347
+            'brand_id'        => $product['brand_id'] ?? null,
348
+            'cate_id'         => $product['cate_id'] ?? 0,
349
+            'mer_cate_id'     => [], // 商户分类,保持空数组
350
+            'unit_name'       => $product['unit_name'] ?? '件',
351
+            'sort'            => $product['sort'] ?? 0,
352
+            'is_good'         => $product['is_good'] ?? 0,
353
+            'temp_id'         => $product['temp_id'] ?? 0,
354
+            'attr'            => $attr,
355
+            'content'         => $content ?? '',
356
+            'spec_type'       => $product['spec_type'] ?? 1,
357
+            'extension_type'  => $profitConfig['extension_type'],
358
+            'give_coupon_ids' => [],
359
+            'is_gift_bag'     => $product['is_gift_bag'] ?? 0,
360
+            'type'            => $product['type'] ?? 1,
361
+            'commission'      => $product['commission'] ?? '',
362
+            'pension'         => (string)($product['pension'] ?? '0.00'),
363
+            'pension_is'      => $product['pension_is'] ?? 0,
364
+            'share_is'        => $product['share_is'] ?? 0,
365
+            'ficti'           => $product['ficti'] ?? 0,
366
+            'icon_type'       => !empty($product['icon_type'])
367
+                ? (is_string($product['icon_type']) ? json_decode($product['icon_type'], true) : $product['icon_type'])
368
+                : [],
369
+            'attrValue'       => $attrValue,
370
+        ];
371
+
372
+        // 9. 调用 ProductRepository::update() 执行更新
373
+        /** @var ProductRepository $productRepository */
374
+        $productRepository = app()->make(ProductRepository::class);
375
+        $productRepository->update($productId, $updateData, $merId);
376
+    }
377
+
378
+    /**
283 379
      * 根据售价计算原价(阶梯加价)
284 380
      *
285 381
      * @param float $salePrice SKU售价