diff --git a/app/Admin/Extensions/Grid/Tools/Product/BatchSkuSyncSpu.php b/app/Admin/Extensions/Grid/Tools/Product/BatchSkuSyncSpu.php index 05c97791..583463e4 100644 --- a/app/Admin/Extensions/Grid/Tools/Product/BatchSkuSyncSpu.php +++ b/app/Admin/Extensions/Grid/Tools/Product/BatchSkuSyncSpu.php @@ -64,6 +64,7 @@ class BatchSkuSyncSpu extends BatchAction } catch (Throwable $th) { DB::rollBack(); report($th); + return $this->response()->error('操作失败:'.$th->getMessage())->refresh(); } $message = '操作成功'; diff --git a/app/Admin/Extensions/Grid/Tools/Product/InitSkuBySpecs.php b/app/Admin/Extensions/Grid/Tools/Product/InitSkuBySpecs.php index 743c88ab..b1c17bed 100644 --- a/app/Admin/Extensions/Grid/Tools/Product/InitSkuBySpecs.php +++ b/app/Admin/Extensions/Grid/Tools/Product/InitSkuBySpecs.php @@ -6,7 +6,8 @@ use App\Models\ProductSku; use App\Models\ProductSpu; use Dcat\Admin\Grid\Tools\AbstractTool; use Illuminate\Http\Request; -use Illuminate\Support\Arr; +use Illuminate\Support\Facades\DB; +use Throwable; class InitSkuBySpecs extends AbstractTool { @@ -55,53 +56,16 @@ class InitSkuBySpecs extends AbstractTool $nowTime = now(); //获取SPU $spu = ProductSpu::with('specs')->findOrFail($this->getKey()); - $skuSpecs = []; - foreach ($spu->specs as $spec) { - $_items = []; - foreach ($spec->items as $item) { - $_items[] = [ - 'id' => $spec->id, - 'name'=>$item['name'], - 'price'=>$item['value'], - ]; - } - $skuSpecs[] = $_items; + try { + DB::beginTransaction(); + ProductSku::createBySpu($spu); + DB::commit(); + } catch (Throwable $th) { + DB::rollBack(); + report($th); + return $this->response()->error(__('admin.update_failed').': '.$th->getMessage())->refresh(); } - //生成规格笛卡尔集 - $skuSpecs = Arr::crossJoin(...$skuSpecs); - $insertData = []; - //根据规格笛卡尔集生成预插入数据 - foreach ($skuSpecs as $skuSpec) { - $_skuSpecs = []; - $_price = 0; - foreach ($skuSpec as $value) { - $_skuSpecs[$value['id']] = $value['name']; - $_price += $value['price']; - } - $insertData[] = [ - 'spu_id' => $spu->id, - 'name' => trim($spu->name.' '.implode(' ', $_skuSpecs)), - 'subtitle' => $spu->subtitle, - 'category_id' => $spu->category_id, - 'cover' => $spu->cover, - 'images' => json_encode($spu->images), - 'description' => $spu->description, - 'sell_price' => bcadd($spu->sell_price, bcmul($_price, 100)), - 'market_price' => $spu->market_price, - 'cost_price' => $spu->cost_price, - 'vip_price' => !is_null($spu->vip_price) ? bcadd($spu->vip_price, bcmul($_price, 100)) : null, - 'media' => $spu->media, - 'weight' => $spu->weight, - 'attrs' => json_encode($spu->attrs), - 'specs' => json_encode($_skuSpecs), - 'stock' => $spu->stock, - 'sales' => $spu->sales, - 'buynote_id' => $spu->buynote_id, - 'created_at' => $nowTime, - 'updated_at' => $nowTime, - ]; - } - count($insertData)>0 && ProductSku::insert($insertData); + return $this->response()->success(__('admin.update_succeeded'))->refresh(); } diff --git a/app/Admin/Forms/AddSku.php b/app/Admin/Forms/AddSku.php index 2b92564a..cfa6e09c 100644 --- a/app/Admin/Forms/AddSku.php +++ b/app/Admin/Forms/AddSku.php @@ -8,6 +8,8 @@ use App\Models\ProductSpuSpec; use Dcat\Admin\Contracts\LazyRenderable; use Dcat\Admin\Traits\LazyWidget; use Dcat\Admin\Widgets\Form; +use Illuminate\Support\Facades\DB; +use Throwable; class AddSku extends Form implements LazyRenderable { @@ -44,26 +46,18 @@ class AddSku extends Form implements LazyRenderable return $this->response()->error(__('admin_message.forms.add_sku.errors.has_specs')); } else { $spu = ProductSpu::findOrFail($spuId); - ProductSku::create([ - 'spu_id' => $spu->id, - 'name' => trim($spu->name.' '.implode(' ', $_skuSpecs)), - 'subtitle' => $spu->subtitle, - 'category_id' => $spu->category_id, - 'cover' => $spu->cover, - 'images' => $spu->images, - 'description' => $spu->description, - 'sell_price' => bcadd($spu->sell_price, $_price), - 'market_price' => $spu->market_price, - 'cost_price' => $spu->cost_price, - 'vip_price' => !is_null($spu->vip_price) ? bcadd($spu->vip_price, $_price) : null, - 'media' => $spu->media, - 'weight' => $spu->weight, - 'attrs' => $spu->attrs, - 'specs' => $_skuSpecs, - 'stock' => $spu->stock, - 'sales' => $spu->sales, - 'buynote_id' => $spu->buynote_id, - ]); + try { + DB::beginTransaction(); + ProductSku::createBySpec([ + 'specs'=>$_skuSpecs, + 'price'=>$_price, + ], $spu); + DB::commit(); + } catch (Throwable $th) { + DB::rollBack(); + report($th); + return $this->response()->error('操作失败:'.$th->getMessage())->refresh(); + } } } return $this->response() diff --git a/app/Admin/Renderable/ProductSkuTable.php b/app/Admin/Renderable/ProductSkuTable.php index 34cdb77e..ecad5eff 100644 --- a/app/Admin/Renderable/ProductSkuTable.php +++ b/app/Admin/Renderable/ProductSkuTable.php @@ -6,10 +6,14 @@ use App\Admin\Actions\Grid\ReleaseCancel; use App\Admin\Actions\Grid\ReleaseDown; use App\Admin\Actions\Grid\ReleaseUp; use App\Admin\Actions\Grid\SkuSyncSpu; +use App\Admin\Extensions\Grid\Tools\Product\AddSku; use App\Admin\Extensions\Grid\Tools\Product\BatchReleaseCancel; use App\Admin\Extensions\Grid\Tools\Product\BatchReleaseDown; use App\Admin\Extensions\Grid\Tools\Product\BatchReleaseUp; +use App\Admin\Extensions\Grid\Tools\Product\InitSkuBySpecs; +use App\Admin\Extensions\Grid\Tools\Product\SettingSpecs; use App\Models\ProductSku; +use App\Models\ProductSpu; use Dcat\Admin\Admin; use Dcat\Admin\Grid; @@ -18,9 +22,7 @@ class ProductSkuTable extends Grid public static function grid(int $spuId = null) { $builder = ProductSku::with('category'); - if ($spuId) { - $builder->where('spu_id', $spuId); - } + $grid = parent::make($builder, function (Grid $grid) { $grid->setResource('product-skus'); $grid->showRowSelector(); @@ -91,6 +93,26 @@ class ProductSkuTable extends Grid $filter->equal('name')->width(3); }); }); + + if ($spuId) { + $grid->model()->where('spu_id', $spuId); + $spu = ProductSpu::findOrFail($spuId); + $grid->tools(function (Grid\Tools $tools) use ($spu) { + //设置规格 + if (Admin::user()->can('dcat.admin.product_spus.setting_specs')) { + $tools->append(new SettingSpecs($spu->id)); + } + if ($spu->hasSku()) { //下面有sku,手动创建sku + if (Admin::user()->can('dcat.admin.product_spus.add_sku')) { + $tools->append(new AddSku($spu->id)); + } + } else {//下面无sku,根据规格自动生成sku + if (Admin::user()->can('dcat.admin.product_spus.init_sku_by_specs')) { + $tools->append(new InitSkuBySpecs($spu->id)); + } + } + }); + } return $grid; } } diff --git a/app/Models/ProductSku.php b/app/Models/ProductSku.php index 012ba74c..b6c5643d 100644 --- a/app/Models/ProductSku.php +++ b/app/Models/ProductSku.php @@ -5,6 +5,7 @@ namespace App\Models; use App\Casts\JsonArray; use App\Casts\Price; use App\Traits\Release; +use App\Traits\SkuInfo; use Dcat\Admin\Traits\HasDateTimeFormatter; use EloquentFilter\Filterable; use Illuminate\Database\Eloquent\Model; @@ -14,6 +15,7 @@ class ProductSku extends Model use Filterable; use HasDateTimeFormatter; use Release; + use SkuInfo; public const STATUS_INVALID = -1; // 无效的 public const STATUS_ONLINE = 1; // 已上架 diff --git a/app/Traits/Release.php b/app/Traits/Release.php index c39e877f..d143dc27 100644 --- a/app/Traits/Release.php +++ b/app/Traits/Release.php @@ -142,7 +142,7 @@ trait Release } $sku->update( [ - 'name' => trim($sku->spu->name.' '.implode(',', $sku->specs)), + 'name' => trim($sku->spu->name.' '.implode(' ', $sku->specs)), 'subtitle'=> $sku->spu->subtitle, 'cover' => $sku->spu->cover, // 'images' => $sku->spu->images, diff --git a/app/Traits/SkuInfo.php b/app/Traits/SkuInfo.php new file mode 100644 index 00000000..5ed06813 --- /dev/null +++ b/app/Traits/SkuInfo.php @@ -0,0 +1,209 @@ +specs as $spec) { + $_items = []; + foreach ($spec->items as $item) { + $_items[] = [ + 'id' => $spec->id, + 'name'=>$item['name'], + 'price'=>$item['value'], + ]; + } + $skuSpecs[] = $_items; + } + //生成规格笛卡尔集 + return Arr::crossJoin(...$skuSpecs); + } + + /** + * 根据SPEC和spu返回 skuInfo + * + * @param [type] $skuSpec + * @param ProductSpu $spu + * @return array + */ + protected static function createInfo(array $skuSpec, ProductSpu $spu): array + { + return [ + 'spu_id' => $spu->id, + 'name' => static::createName($spu->name, $skuSpec['specs']), + 'subtitle' => $spu->subtitle, + 'category_id' => $spu->category_id, + 'cover' => $spu->cover, + 'images' => $spu->images, + 'description' => $spu->description, + 'sell_price' => static::createSellPrice((float) $spu->sell_price, (float) $skuSpec['price']), + 'market_price' => static::createMarketPrice((float) $spu->market_price, (float) $skuSpec['price']), + 'cost_price' => static::createCostPrice((float) $spu->cost_price, (float) $skuSpec['price']), + 'vip_price' => static::createVipPrice($spu->vip_price, (float) $skuSpec['price']), + 'media' => $spu->media, + 'weight' => $spu->weight, + 'attrs' => $spu->attrs, + 'specs' => $skuSpec['specs'], + 'buynote_id' => $spu->buynote_id, + 'verify_state' => 0, //默认为正常 + ]; + } + + public static function createBySpu(ProductSpu $spu) + { + $nowTime = now(); + $insertData = []; + //根据规格笛卡尔集生成预插入数据 + foreach (static::specCross($spu) as $skuSpec) { + $_skuSpecs = []; + $_price = 0; + foreach ($skuSpec as $value) { + $_skuSpecs[$value['id']] = $value['name']; + $_price += $value['price']; + } + $_data = static::createInfo([ + 'specs'=>$_skuSpecs, + 'price'=>$_price, + ], $spu, 'create'); + + //批量插入时特殊单独处理数据 + $_data['sell_price'] = (int) bcmul($_data['sell_price'], 100); + $_data['market_price'] = (int) bcmul($_data['market_price'], 100); + $_data['cost_price'] = (int) bcmul($_data['cost_price'], 100); + $_data['vip_price'] = !is_null($_data['vip_price']) ? (int) bcmul($_data['vip_price'], 100) : null; + + $_data['images'] = json_encode($_data['images']); + $_data['attrs'] = json_encode($_data['attrs']); + $_data['specs'] = json_encode($_data['specs']); + + //初始化时添加额外的数据 + $_data['stock'] = $spu->stock; + $_data['sales'] = $spu->sales; + $_data['created_at'] = $nowTime; + $_data['updated_at'] = $nowTime; + $insertData[] = $_data; + } + count($insertData)>0 && ProductSku::insert($insertData); + } + + /** + * 根据规格生成商品 + * + * @return void + */ + public static function createBySpec(array $skuSpec, ProductSpu $spu) + { + $data = static::createInfo($skuSpec, $spu); + ProductSku::create($data); + } + + /** + * 根据skuID同步主商品 + * + * @param integer|null $id + * @return void + */ + public static function syncSpuById(int $id= null) + { + static::syncSpu(ProductSku::with('spu')->findOrFail($id)); + } + + /** + * 同步主商品 + * + * @param ProductSku $sku + * @return void + */ + public static function syncSpu(ProductSku $sku) + { + $_price = 0; + foreach ($sku->specs as $id => $value) { + $spuSpec = $sku->spu->specs->first(function ($item) use ($id) { + return $item->id == $id; + }); + foreach ($spuSpec->items as $item) { + if ($item['name'] == $value) { + $_price += $item['value']; + } + } + } + + $sku->update(static::createInfo([ + 'specs'=>$sku->specs, + 'price'=>$_price, + ], $sku->spu)); + } +}