海南旅游SAAS
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.

215 lines
7.5 KiB

  1. <?php
  2. namespace App\AdminAgent\Forms;
  3. use App\AdminAgent\Renderable\SelectIndustryProductSpec;
  4. use App\Common\OrderStatus;
  5. use App\Common\PayType;
  6. use App\Common\ProductStatus;
  7. use App\Models\IndustryOrder;
  8. use App\Models\IndustryProduct;
  9. use App\Models\IndustryProductSpec;
  10. use Dcat\Admin\Admin;
  11. use Dcat\Admin\Widgets\Alert;
  12. use Dcat\Admin\Widgets\Form;
  13. use Illuminate\Support\Facades\DB;
  14. class IndustryProductBuy extends Form
  15. {
  16. /**
  17. * Handle the form request.
  18. *
  19. * @param array $input
  20. *
  21. * @return mixed
  22. */
  23. public function handle(array $input)
  24. {
  25. $pid = request()->input('pid');
  26. $industry = IndustryProduct::with('diyForm')->where([
  27. ['status', '=', ProductStatus::ON_SALE],
  28. ['stock', '>', 0],
  29. ])->find($pid);
  30. if (!$industry) {
  31. return $this->response()->error('产品不存在或已下架');
  32. }
  33. //最小起购数
  34. if ($input['num'] < $industry->min_sale) {
  35. return $this->response()->error('购买数量不能小于最低起购数:' . $industry->min_sale);
  36. }
  37. //产品规格
  38. $spec = IndustryProductSpec::where([
  39. ['industry_product_id', '=', $industry->id],
  40. ['stock', '>=', $input['num']],
  41. ])->find($input['industry_product_spec_id']);
  42. if (!$spec) {
  43. return $this->response()->error('产品规格不存在或库存不足');
  44. }
  45. //信息收集表处理,保留字段类型等信息,便于后台显示
  46. $order_info = $input['info'] ?? [];
  47. if (!empty($industry->diyForm->fields) && !$industry->diyForm->fields->isEmpty()) {
  48. $fields = array_column($industry->diyForm->fields->toArray(), null, 'field');
  49. foreach ($fields as &$field) {
  50. if ($field['required'] && !isset($order_info[$field['field']])) { //判断是否必填
  51. return $this->error($field['field'] . '不能为空');
  52. }
  53. $field['value'] = $order_info[$field['field']] ?? '';
  54. }
  55. $order_info = $fields;
  56. }
  57. //生成订单号
  58. list($micro, $sec) = explode(' ', microtime());
  59. $micro = str_pad(floor($micro * 1000000), 6, 0, STR_PAD_LEFT);
  60. $order_no = date('ymdHis', $sec) . $micro . mt_rand(1000, 9999);
  61. DB::beginTransaction();
  62. try {
  63. //规格减库存
  64. $affect_row = IndustryProductSpec::where([
  65. ['id', '=', $spec->id],
  66. ['stock', '>=', $input['num']],
  67. ])->decrement('stock', $input['num']);
  68. if (!$affect_row) {
  69. throw new \Exception('产品规格库存不足!');
  70. }
  71. //产品表减库存
  72. $industry->stock = $industry->stock - $input['num'];
  73. $industry->save();
  74. if ($input['pay_type'] == PayType::DEPOSIT_PAY) {
  75. $prepay_price = $industry->deposit * $input['num'];
  76. } else if ($input['pay_type'] == PayType::EARNEST_PAY) {
  77. $prepay_price = $industry->earnest * $input['num'];
  78. } else {
  79. $prepay_price = 0;
  80. }
  81. $order = IndustryOrder::create([
  82. 'agent_id' => Admin::user()->id,
  83. 'supplier_id' => $industry->supplier_id,
  84. 'order_no' => $order_no,
  85. 'industry_product_id' => $industry->id,
  86. 'industry_product_spec_id' => $input['industry_product_spec_id'],
  87. 'num' => $input['num'],
  88. 'price' => $input['num'] * $spec['price'],
  89. 'name' => $input['name'],
  90. 'mobile' => $input['mobile'],
  91. 'title' => $industry->title,
  92. 'picture' => $industry->pictures[0] ?? '',
  93. 'status' => $input['pay_type'] == PayType::OFFLINE ? OrderStatus::OFFLINE_UNPAID : OrderStatus::UNPAID,
  94. 'pay_type' => $input['pay_type'],
  95. 'paid_money' => 0,
  96. 'paid_at' => null,
  97. 'trade_deposit' => $industry->single_deposit * $input['num'],
  98. 'timeout' => null,
  99. 'created_at' => now(),
  100. 'prepay_price' => $prepay_price,
  101. 'single_price' => $industry->single_deposit,
  102. 'info' => $order_info,
  103. ]);
  104. DB::commit();
  105. return $this->response()->success('购买成功,等待供应商审核')->redirect(admin_url('industry_order/list'));
  106. } catch (\Exception $e) {
  107. DB::rollBack();
  108. return $this->response()->error($e->getMessage());
  109. }
  110. }
  111. /**
  112. * Build a form here.
  113. */
  114. public function form()
  115. {
  116. //处理图片上传
  117. $_file = request()->file('_file_');
  118. if ($_file && $_file->isValid()) {
  119. $this->multipleImage(request()->input('upload_column'))->uniqueName()->saveFullUrl();
  120. return true;
  121. }
  122. $pid = request()->input('pid');
  123. $industry = IndustryProduct::with('diyForm.fields')
  124. ->where([
  125. ['status', '=', ProductStatus::ON_SALE],
  126. ['stock', '>', 0],
  127. ])->find($pid);
  128. if (!$industry) {
  129. return $this->response()->error('产品不存在或已下架');
  130. }
  131. Admin::translation('industry-order');
  132. $this->selectTable('industry_product_spec_id', '选择产品规格')
  133. ->required()
  134. ->title('选择产品规格')
  135. ->dialogWidth('80%;min-width:825px;')
  136. ->from(SelectIndustryProductSpec::make(['industry_product_id' => $pid]))
  137. ->model(IndustryProductSpec::class);
  138. //购买人信息
  139. $this->hidden('pid')->value($industry->id); //pid要跟上面的request中的一样,否则提交出错
  140. $this->number('num')->min($industry->min_sale)->required()->default($industry->min_sale);
  141. $this->text('name', '您的姓名')->default(Admin::user()->director)->required();
  142. $this->mobile('mobile', '您的手机号')->default(Admin::user()->contact_phone)->required();
  143. //支付信息
  144. $pay_type = [PayType::ONLINE, PayType::OFFLINE];
  145. if ((float)$industry->deposit) { //订金支付
  146. $pay_type = [...$pay_type, PayType::DEPOSIT_PAY];
  147. }
  148. if ((float)$industry->earnest) { //定金支付
  149. $pay_type = [...$pay_type, PayType::EARNEST_PAY];
  150. }
  151. $options = array_filter(PayType::array(), fn($k) => in_array($k, $pay_type), ARRAY_FILTER_USE_KEY);
  152. $this->select('pay_type')
  153. ->options($options)->default(PayType::ONLINE)->required()
  154. ->when(PayType::DEPOSIT_PAY, function () use ($industry) {
  155. $this->display('deposit', '订金')->customFormat(fn() => $industry->deposit);
  156. })->when(PayType::EARNEST_PAY, function () use ($industry) {
  157. $this->display('earnest', '定金')->customFormat(fn() => $industry->earnest);
  158. });
  159. //信息收集表单
  160. if (!empty($industry->diyForm->fields)) {
  161. $this->html(Alert::make(null, '客户信息收集表单')->warning())->width(12);
  162. $fields = $industry->diyForm->fields->toArray();
  163. foreach ($fields as $v) {
  164. if ($v['type'] == 'radio' || $v['type'] == 'checkbox') {
  165. $this->{$v['type']}('info.' . $v['field'])->options(array_combine($v['options'], $v['options']))->required((bool)$v['required']);
  166. } else if ($v['type'] == 'image') {
  167. $this->multipleImage('info.' . $v['field'])->uniqueName()->saveFullUrl()->required((bool)$v['required']);
  168. } else if ($v['type'] == 'datetime') {
  169. $this->datetime('info.' . $v['field'])->format($v['format'] ?? 'YYYY-MM-DD HH:mm')->required((bool)$v['required']);
  170. } else {
  171. $this->{$v['type']}('info.' . $v['field'])->required((bool)$v['required']);
  172. }
  173. }
  174. }
  175. $this->html(Alert::make(null, '产品信息确认')->info())->width(12);
  176. $this->text('', '购买产品')->default($industry->title)->disable();
  177. $this->text('', '单价')->default($industry->price)->disable();
  178. $this->text('', '库存')->default($industry->stock)->disable();
  179. $this->text('', '起购数量')->default($industry->min_sale)->disable();
  180. $this->multipleImage('pictures', '产品图')->default($industry->pictures)->disable();
  181. $this->display('', '旅游须知')->default(fn() => preg_replace('/<script.*?>.*?<\/script>/is', '', $industry->know))->disable();
  182. $this->display('', '产品详情')->default(fn() => preg_replace('/<script.*?>.*?<\/script>/is', '', $industry->content))->disable();
  183. }
  184. /**
  185. * The data of the form.
  186. *
  187. * @return array
  188. */
  189. public function default()
  190. {
  191. return [];
  192. }
  193. }