diff --git a/MySQL_change.sql b/MySQL_change.sql index 8a2cc04..fd2349e 100644 --- a/MySQL_change.sql +++ b/MySQL_change.sql @@ -304,10 +304,18 @@ ALTER TABLE `industry_orders` ADD COLUMN `paid_money` DECIMAL(20,2) NOT NULL DEFAULT '0.00' COMMENT '已付款金额' AFTER `pay_type`, ADD COLUMN `prepay_price` DECIMAL(8,2) NOT NULL DEFAULT '0.00' COMMENT '下单时产品的订金/定金' AFTER `deleted_at`, ADD COLUMN `prepay_timeout` INT(11) NOT NULL DEFAULT '0' COMMENT '订金/定金支付超时时间,单位:分钟' AFTER `prepay_price`, - ADD COLUMN `single_price` DECIMAL(8,2) NOT NULL DEFAULT '0.00' COMMENT '下单时的单人头交易费' AFTER `prepay_timeout`; + ADD COLUMN `single_price` DECIMAL(8,2) NOT NULL DEFAULT '0.00' COMMENT '下单时的单人头交易费' AFTER `prepay_timeout`, + ADD COLUMN `info` JSON NULL DEFAULT NULL COMMENT '客户信息收集' AFTER `single_price`; + # 17:46 ‎2021/‎10/‎17 ALTER TABLE `products` ADD COLUMN `logitude` DECIMAL(20,14) NOT NULL DEFAULT 0 COMMENT '经度' AFTER `diy_form_id`, ADD COLUMN `latitude` DECIMAL(20,14) NOT NULL DEFAULT 0 COMMENT '纬度' AFTER `logitude`, ADD COLUMN `address` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '地址' AFTER `latitude`; + + + +# 10:43 ‎2021/‎10/‎18 +ALTER TABLE `industry_orders` + CHANGE COLUMN `trade_deposit` `trade_deposit` DECIMAL(20,2) NOT NULL DEFAULT '0.00' COMMENT '需要扣除的交易金' AFTER `prepay_timeout`; diff --git a/app/AdminAgent/Controllers/IndustryOrderController.php b/app/AdminAgent/Controllers/IndustryOrderController.php index d659bce..597aee4 100644 --- a/app/AdminAgent/Controllers/IndustryOrderController.php +++ b/app/AdminAgent/Controllers/IndustryOrderController.php @@ -135,7 +135,7 @@ class IndustryOrderController extends AdminController } else { $msg = $pay_config['return_msg'] ?? '获取支付信息失败'; } - Admin::script("Dcat.swal.info('支付失败:$msg', null);"); + Admin::script("Dcat.swal.info('支付:$msg', null);"); } else { Admin::js('@qrcode'); Admin::script(<<input('pid'); - $industry = IndustryProduct::where([ - ['status', '=', ProductStatus::ON_SALE], - ['stock', '>', 0], - ])->find($pid); + $industry = IndustryProduct::with('diyForm.fields') + ->where([ + ['status', '=', ProductStatus::ON_SALE], + ['stock', '>', 0], + ])->find($pid); return Form::make(new IndustryOrder(), function (Form $form) use ($industry) { if (!$industry) { @@ -240,6 +241,19 @@ JS $options = array_filter(PayType::array(), fn($k) => in_array($k, $pay_type), ARRAY_FILTER_USE_KEY); $form->select('pay_type')->options($options)->default(PayType::ONLINE)->required(); + //信息收集表单 TODO 信息收集表单文件上传不了,不能用事务 + if (!empty($industry->diyForm->fields)) { + $form->divider(); + $fields = $industry->diyForm->fields->toArray(); + foreach ($fields as $v) { + if ($v['type'] == 'radio' || $v['type'] == 'checkbox') { + $form->{$v['type']}('info.' . $v['field'])->options($v['options'])->required((bool)$v['required']); + } else { + $form->{$v['type']}('info.' . $v['field'])->required((bool)$v['required']); + } + } + } + $form->divider(); $form->text('', '购买产品')->default($industry->title)->disable(); $form->text('', '单价')->default($industry->price)->disable(); @@ -297,16 +311,20 @@ JS $form->timeout = null; if ($form->pay_type == PayType::DEPOSIT_PAY) { - $form->prepay_price = $industry->deposit; + $form->prepay_price = $industry->deposit * $form->num; } else if ($form->pay_type == PayType::EARNEST_PAY) { - $form->prepay_price = $industry->earnest; + $form->prepay_price = $industry->earnest * $form->num; } else { $form->prepay_price = 0; } + + //产品规格表减库存 + $spec->stock = $spec->stock - $form->num; + $spec->save(); })->saved(function (Form $form) { return $form->response()->success('下单成功,请等待供应商审核订单')->redirect(admin_url('industry_order/list')); })->deleting(function (Form $form) { return $form->response()->error('操作禁止'); }); - } + }*/ } diff --git a/app/AdminAgent/Controllers/IndustryProductController.php b/app/AdminAgent/Controllers/IndustryProductController.php index 4654036..a66771a 100644 --- a/app/AdminAgent/Controllers/IndustryProductController.php +++ b/app/AdminAgent/Controllers/IndustryProductController.php @@ -2,11 +2,15 @@ namespace App\AdminAgent\Controllers; +use App\AdminAgent\Forms\IndustryProductBuy; use App\AdminAgent\Repositories\IndustryProduct; use App\Common\ProductStatus; +use Dcat\Admin\Admin; use Dcat\Admin\Grid; +use Dcat\Admin\Layout\Content; use Dcat\Admin\Show; use Dcat\Admin\Http\Controllers\AdminController; +use Dcat\Admin\Widgets\Card; class IndustryProductController extends AdminController { @@ -41,7 +45,7 @@ class IndustryProductController extends AdminController ->if(fn() => true) ->then(function ($column) { $column->append('查看  '); - $column->append('购买'); + $column->append('购买'); }); $grid->filter(function (Grid\Filter $filter) { @@ -84,4 +88,16 @@ class IndustryProductController extends AdminController $show->field('updated_at'); }); } + + //购买行业产品 + public function buy(Content $content): Content + { + $pid = request()->input('pid'); + if (!$pid) { + Admin::exit('未指定要购买的产品'); + } + return $content + ->title('购买行业产品') + ->body(new Card(new IndustryProductBuy())); + } } diff --git a/app/AdminAgent/Forms/IndustryProductBuy.php b/app/AdminAgent/Forms/IndustryProductBuy.php new file mode 100644 index 0000000..2245526 --- /dev/null +++ b/app/AdminAgent/Forms/IndustryProductBuy.php @@ -0,0 +1,200 @@ +input('pid'); + + $industry = IndustryProduct::where([ + ['status', '=', ProductStatus::ON_SALE], + ['stock', '>', 0], + ])->find($pid); + if (!$industry) { + return $this->response()->error('产品不存在或已下架'); + } + + //最小起购数 + if ($input['num'] < $industry->min_sale) { + return $this->response()->error('购买数量不能小于最低起购数:' . $industry->min_sale); + } + + //产品规格 + $spec = IndustryProductSpec::where([ + ['industry_product_id', '=', $industry->id], + ['stock', '>=', $input['num']], + ])->find($input['industry_product_spec_id']); + if (!$spec) { + return $this->response()->error('产品规格不存在或库存不足'); + } + + //生成订单号 + list($micro, $sec) = explode(' ', microtime()); + $micro = str_pad(floor($micro * 1000000), 6, 0, STR_PAD_LEFT); + $order_no = date('ymdHis', $sec) . $micro . mt_rand(1000, 9999); + + DB::beginTransaction(); + try { + //规格减库存 + $allow_row = IndustryProductSpec::where([ + ['id', '=', $spec->id], + ['stock', '>=', $input['num']], + ])->decrement('stock', $input['num']); + if (!$allow_row) { + throw new \Exception('产品规格库存不足!'); + } + + //产品表减库存 + $industry->stock = $industry->stock - $input['num']; + $industry->save(); + + if ($input['pay_type'] == PayType::DEPOSIT_PAY) { + $prepay_price = $industry->deposit * $input['num']; + } else if ($input['pay_type'] == PayType::EARNEST_PAY) { + $prepay_price = $industry->earnest * $input['num']; + } else { + $prepay_price = 0; + } + + $order = IndustryOrder::create([ + 'agent_id' => Admin::user()->id, + 'supplier_id' => $industry->supplier_id, + 'order_no' => $order_no, + 'industry_product_id' => $industry->id, + 'industry_product_spec_id' => $input['industry_product_spec_id'], + 'num' => $input['num'], + 'price' => $input['num'] * $spec['price'], + 'name' => $input['name'], + 'mobile' => $input['mobile'], + 'title' => $industry->title, + 'picture' => $industry->pictures[0] ?? '', + 'status' => $input['pay_type'] == PayType::OFFLINE ? OrderStatus::OFFLINE_UNPAID : OrderStatus::UNPAID, + 'pay_type' => $input['pay_type'], + 'paid_money' => 0, + 'paid_at' => null, + 'trade_deposit' => $industry->single_deposit * $input['num'], + 'timeout' => null, + 'created_at' => now(), + 'prepay_price' => $prepay_price, + 'single_price' => $industry->single_deposit, + 'info' => json_encode($input['info']), + ]); + + DB::commit(); + return $this->response()->success('购买成功!')->redirect('industry_order/list/' . $order->id); + } catch (\Exception $e) { + DB::rollBack(); + return $this->response()->error($e->getMessage()); + } + } + + /** + * Build a form here. + */ + public function form() + { + //处理图片上传 + $_file = request()->file('_file_'); + if ($_file && $_file->isValid()) { + $this->image(request()->input('upload_column'))->uniqueName()->saveFullUrl(); + return true; + } + + $pid = request()->input('pid'); + $industry = IndustryProduct::with('diyForm.fields') + ->where([ + ['status', '=', ProductStatus::ON_SALE], + ['stock', '>', 0], + ])->find($pid); + + if (!$industry) { + return $this->response()->error('产品不存在或已下架'); + } + Admin::translation('industry-order'); + + $this->selectTable('industry_product_spec_id', '选择产品规格') + ->required() + ->title('选择产品规格') + ->dialogWidth('80%;min-width:825px;') + ->from(SelectIndustryProductSpec::make(['industry_product_id' => $pid])) + ->model(IndustryProductSpec::class); + + //购买人信息 + $this->hidden('pid')->value($industry->id); //pid要跟上面的request中的一样,否则提交出错 + $this->number('num')->min($industry->min_sale)->required()->default($industry->min_sale); + $this->text('name', '您的姓名')->default(Admin::user()->director)->required(); + $this->mobile('mobile', '您的手机号')->default(Admin::user()->contact_phone)->required(); + + //支付信息 + $pay_type = [PayType::ONLINE, PayType::OFFLINE]; + if ((float)$industry->deposit) { //订金支付 + $pay_type = [...$pay_type, PayType::DEPOSIT_PAY]; + } + if ((float)$industry->earnest) { //定金支付 + $pay_type = [...$pay_type, PayType::EARNEST_PAY]; + } + $options = array_filter(PayType::array(), fn($k) => in_array($k, $pay_type), ARRAY_FILTER_USE_KEY); + $this->select('pay_type') + ->options($options)->default(PayType::ONLINE)->required() + ->when(PayType::DEPOSIT_PAY, function () use ($industry) { + $this->display('deposit', '订金')->customFormat(fn() => $industry->deposit); + })->when(PayType::EARNEST_PAY, function () use ($industry) { + $this->display('earnest', '定金')->customFormat(fn() => $industry->earnest); + }); + + //信息收集表单 + if (!empty($industry->diyForm->fields)) { + $this->html(Alert::make(null, '客户信息收集表单')->warning())->width(12); + $fields = $industry->diyForm->fields->toArray(); + foreach ($fields as $v) { + if ($v['type'] == 'radio' || $v['type'] == 'checkbox') { + $this->{$v['type']}('info.' . $v['field'])->options(array_combine($v['options'], $v['options']))->required((bool)$v['required']); + } else if ($v['type'] == 'image') { + $this->image('info.' . $v['field'])->uniqueName()->saveFullUrl()->required((bool)$v['required']); + } else { + $this->{$v['type']}('info.' . $v['field'])->required((bool)$v['required']); + } + } + } + + $this->html(Alert::make(null, '产品信息')->info())->width(12); + $this->text('', '购买产品')->default($industry->title)->disable(); + $this->text('', '单价')->default($industry->price)->disable(); + $this->text('', '库存')->default($industry->stock)->disable(); + $this->text('', '起购数量')->default($industry->min_sale)->disable(); + $this->image('picture', '产品图')->default($industry->pictures)->disable(); + $this->display('', '旅游须知')->default(fn() => preg_replace('/.*?<\/script>/is', '', $industry->know))->disable(); + $this->display('', '产品详情')->default(fn() => preg_replace('/.*?<\/script>/is', '', $industry->content))->disable(); + } + + /** + * The data of the form. + * + * @return array + */ + public function default() + { + return []; + } +} diff --git a/app/AdminAgent/routes.php b/app/AdminAgent/routes.php index 76f104c..f340f54 100644 --- a/app/AdminAgent/routes.php +++ b/app/AdminAgent/routes.php @@ -24,6 +24,7 @@ Route::group([ $router->resource('special/list', 'SpecialController'); $router->resource('industry_product/list', 'IndustryProductController'); + $router->get('industry_product/buy', 'IndustryProductController@buy'); $router->resource('industry_order/list', 'IndustryOrderController'); $router->get('industry_order/qrcode/{verify_code}', 'IndustryOrderController@qrcode'); diff --git a/app/Models/IndustryOrder.php b/app/Models/IndustryOrder.php index 86d243b..e199fdc 100644 --- a/app/Models/IndustryOrder.php +++ b/app/Models/IndustryOrder.php @@ -10,6 +10,8 @@ class IndustryOrder extends BaseModel use HasDateTimeFormatter; use SoftDeletes; + protected $guarded = ['id']; + public function supplier() { return $this->belongsTo(Supplier::class)->withTrashed(); diff --git a/resources/lang/zh_CN/industry-order.php b/resources/lang/zh_CN/industry-order.php index e0c5a73..aa01256 100644 --- a/resources/lang/zh_CN/industry-order.php +++ b/resources/lang/zh_CN/industry-order.php @@ -4,6 +4,8 @@ return [ 'IndustryOrder' => '行业产品订单', 'industry-order' => '行业产品订单', 'industry_order' => '行业产品订单', + 'industry_product' => '行业产品', + 'buy' => '购买', ], 'fields' => [ 'supplier_id' => '供应商ID',