StoreOrder.php 112 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257
  1. <?php
  2. namespace addons\Store\common\models;
  3. use addons\Clerk\common\models\ClerkLog;
  4. use addons\Community\common\service\HeadService;
  5. use addons\PaySuccessJump\common\service\JumpUrlService;
  6. use addons\ShoppingLottery\common\helper\LotteryHelper;
  7. use addons\Store\common\enums\StoreEnum;
  8. use addons\Store\common\events\order\ComputeCommissionEvent;
  9. use addons\Store\common\events\order\OrderCreateEvent;
  10. use addons\Store\common\events\order\OrderFinishEvent;
  11. use addons\Store\common\events\order\OrderPaidEvent;
  12. use addons\Store\common\events\order\OrderTakeDeliveryEvent;
  13. use addons\Store\common\events\order\StoreSelfPickupOrderClerkEvent;
  14. use common\enums\AddonsEnum;
  15. use common\enums\ClerkEnum;
  16. use common\enums\MarketingTypeEnum;
  17. use common\enums\OrderSourceEnum;
  18. use common\enums\OrderStatusEnum;
  19. use common\enums\PayTypeEnum;
  20. use common\enums\RedisKeyEnum;
  21. use common\enums\RefundTypeEnum;
  22. use common\enums\ShippingTypeEnum;
  23. use common\enums\StatusEnum;
  24. use common\enums\UserWalletEnum;
  25. use common\globals\GlobalInvoke;
  26. use common\helpers\LockHelper;
  27. use common\helpers\StringHelper;
  28. use common\models\base\BaseActiveRecord;
  29. use common\models\common\PaymentTradeOrder;
  30. use common\models\common\Region;
  31. use common\models\common\ScoreLog;
  32. use common\models\mall\MallAddons;
  33. use common\models\order\Order;
  34. use common\models\order\OrderComments;
  35. use common\models\order\OrderDetail;
  36. use common\models\order\OrderExpress;
  37. use common\models\order\OrderExpressLog;
  38. use common\models\order\OrderMarketing;
  39. use common\models\order\OrderRefund;
  40. use common\models\order\OrderReserve;
  41. use common\models\order\OrderUserHandle;
  42. use common\models\user\User;
  43. use services\common\UserWalletService;
  44. use Yii;
  45. use Exception;
  46. use yii\helpers\Json;
  47. use common\models\common\Download;
  48. use common\models\user\UserPartitionRelationship;
  49. use common\components\export\CsvTool;
  50. use common\models\goods\Goods;
  51. use common\models\goods\GoodsAttr;
  52. use common\models\goods\GoodsCate;
  53. use common\models\goods\GoodsCateRelate;
  54. use common\enums\DownloadEnum;
  55. use common\enums\ShippingStatusEnum;
  56. use addons\Mch\common\models\Mch;
  57. /**
  58. * This is the model class for table "qimall_addons_store_order".
  59. *
  60. * @property int $id 订单id
  61. * @property int $mch_id 多商户id,0表示商城订单
  62. * @property int $store_id 门店id,0表示商城订单
  63. * @property int $mall_id 商城ID
  64. * @property int $user_id 用户id
  65. * @property string $order_no 订单编号
  66. * @property string|null $out_trade_no 系统支付流水号
  67. * @property string|null $mobile 收货人的手机号码
  68. * @property int|null $province 收货人所在省
  69. * @property int|null $city 收货人所在城市
  70. * @property int|null $area 收货人所在街道
  71. * @property int $town 镇id
  72. * @property string|null $address 详细地址
  73. * @property string|null $region_name 地区名称(省市区[乡/镇])
  74. * @property string|null $zip 收货人邮编
  75. * @property string|null $receiver_name 收货人姓名
  76. * @property string $remark 用户订单备注
  77. * @property string $seller_remark 商家订单备注
  78. * @property int|null $shipping_type 订单配送方式【1物流配送 2买家自提 3货到付款 4本地配送】
  79. * @property float|null $shipping_money 订单运费
  80. * @property float|null $refund_money 订单退款金额
  81. * @property float|null $pay_money 订单实付金额
  82. * @property float|null $goods_price 商品优惠后总价
  83. * @property float|null $original_goods_price 商品原本总价
  84. * @property string|null $ip 买家ip
  85. * @property int|null $coupon_id 优惠券券id
  86. * @property float|null $coupon_money 优惠券券支付金额
  87. * @property float|null $score 订单消耗积分
  88. * @property float|null $score_money 订单消耗积分抵多少钱
  89. * @property int|null $order_status 订单状态
  90. * @property int|null $pay_status 订单付款状态
  91. * @property int|null $shipping_status 订单配送状态
  92. * @property int|null $review_status 订单评价状态
  93. * @property int|null $is_feedback 订单售后状态:0:未售后;1:售后中;2:售后完成
  94. * @property int|null $payment_type 支付类型
  95. * @property int $marketing_id 营销活动id
  96. * @property string $marketing_type 营销活动类型
  97. * @property int|null $invoice_id 发票id
  98. * @property int|null $status 状态[-1:删除;0:禁用;1启用]
  99. * @property int $is_comment 是否评价 0为未评价 1为已评价 2为已追评
  100. * @property int $is_recycle 是否加入回收站【1是 0否】
  101. * @property int|null $is_virtual 是否包含虚拟商品【1是 0否】
  102. * @property int|null $is_new_user 是否新顾客
  103. * @property int|null $pay_time 订单付款时间
  104. * @property int|null $shipping_time 买家要求配送时间
  105. * @property int|null $sign_time 买家签收时间
  106. * @property int|null $consign_time 卖家发货时间
  107. * @property int|null $finish_time 订单完成时间
  108. * @property int|null $close_time 关闭的时间
  109. * @property string|null $extra_info 额外信息
  110. * @property int|null $created_at 创建时间
  111. * @property int|null $updated_at 更新时间
  112. * @property string|null $order_source 订单来源:juhe_shop=>聚合供应链
  113. * @property int|null $supplier_type 供应者类型:0:自身;1:商城;2:o2o;3:多商户
  114. * @property string|null $clerk_code 核销码
  115. * @property int|null $create_type 创建方式:1:线上下单;2:系统创建
  116. */
  117. class StoreOrder extends BaseActiveRecord
  118. {
  119. /**
  120. * {@inheritdoc}
  121. */
  122. public static function tableName()
  123. {
  124. return '{{%addons_store_order}}';
  125. }
  126. /**
  127. * {@inheritdoc}
  128. */
  129. public function rules()
  130. {
  131. return [
  132. [['mch_id', 'store_id', 'mall_id', 'user_id', 'province', 'city', 'area', 'town', 'community', 'shipping_type', 'coupon_id', 'order_status',
  133. 'pay_status', 'shipping_status', 'review_status', 'is_feedback', 'payment_type', 'marketing_id', 'invoice_id', 'status', 'is_comment',
  134. 'is_recycle', 'is_virtual', 'is_new_user', 'pay_time', 'shipping_time', 'sign_time', 'consign_time', 'finish_time', 'supplier_type', 'close_time',
  135. 'created_at', 'updated_at','create_type'], 'integer'],
  136. [['shipping_money', 'refund_money', 'pay_money', 'goods_price', 'original_goods_price', 'coupon_money', 'score', 'score_money'], 'number'],
  137. [['extra_info'], 'string'],
  138. [['order_no', 'out_trade_no'], 'string', 'max' => 100],
  139. [['mobile'], 'safe'],
  140. [['address', 'region_name'], 'string', 'max' => 200],
  141. [['zip', 'ip'], 'string', 'max' => 20],
  142. [['receiver_name', 'marketing_type'], 'string', 'max' => 50],
  143. [['remark', 'seller_remark', 'order_source'], 'string', 'max' => 255],
  144. [['clerk_code'], 'string', 'max' => 12],
  145. ];
  146. }
  147. /**
  148. * {@inheritdoc}
  149. */
  150. public function attributeLabels()
  151. {
  152. return [
  153. 'id' => '订单id',
  154. 'mch_id' => '多商户id,0表示商城订单',
  155. 'store_id' => '门店id,0表示商城订单',
  156. 'mall_id' => '商城ID',
  157. 'user_id' => '用户id',
  158. 'order_no' => '订单编号',
  159. 'out_trade_no' => '系统支付流水号',
  160. 'mobile' => '收货人的手机号码',
  161. 'province' => '收货人所在省',
  162. 'city' => '收货人所在城市',
  163. 'area' => '收货人所在街道',
  164. 'town' => '镇id',
  165. 'address' => '详细地址',
  166. 'region_name' => '地区名称(省市区[乡/镇])',
  167. 'zip' => '收货人邮编',
  168. 'receiver_name' => '收货人姓名',
  169. 'remark' => '用户订单备注',
  170. 'seller_remark' => '商家订单备注',
  171. 'shipping_type' => '订单配送方式【1物流配送 2买家自提 3货到付款 4本地配送】',
  172. 'shipping_money' => '订单运费',
  173. 'refund_money' => '订单退款金额',
  174. 'pay_money' => '订单实付金额',
  175. 'goods_price' => '商品优惠后总价',
  176. 'original_goods_price' => '商品原本总价',
  177. 'ip' => '买家ip',
  178. 'coupon_id' => '优惠券券id',
  179. 'coupon_money' => '优惠券券支付金额',
  180. 'score' => '订单消耗积分',
  181. 'score_money' => '订单消耗积分抵多少钱',
  182. 'order_status' => '订单状态',
  183. 'pay_status' => '订单付款状态',
  184. 'shipping_status' => '订单配送状态',
  185. 'review_status' => '订单评价状态',
  186. 'is_feedback' => '订单售后状态:0:未售后;1:售后中;2:售后完成',
  187. 'payment_type' => '支付类型',
  188. 'marketing_id' => '营销活动id',
  189. 'marketing_type' => '营销活动类型',
  190. 'invoice_id' => '发票id',
  191. 'status' => '状态[-1:删除;0:禁用;1启用]',
  192. 'is_comment' => '是否评价 0为未评价 1为已评价 2为已追评',
  193. 'is_recycle' => '是否加入回收站【1是 0否】',
  194. 'is_virtual' => '是否包含虚拟商品【1是 0否】',
  195. 'is_new_user' => '是否新顾客',
  196. 'pay_time' => '订单付款时间',
  197. 'shipping_time' => '买家要求配送时间',
  198. 'sign_time' => '买家签收时间',
  199. 'consign_time' => '卖家发货时间',
  200. 'finish_time' => '订单完成时间',
  201. 'close_time' => '关闭的时间',
  202. 'extra_info' => '额外信息',
  203. 'created_at' => '创建时间',
  204. 'updated_at' => '更新时间',
  205. 'order_source' => '订单来源:juhe_shop=>聚合供应链',
  206. 'supplier_type' => '供应者类型:0:自身;1:商城;2:o2o;3:多商户',
  207. 'clerk_code' => '核销码',
  208. 'create_type' => '创建方式:1:线上下单;2:系统创建',
  209. ];
  210. }
  211. public static function fieldsList($field = null)
  212. {
  213. $fields = [
  214. 'order_id' => '订单ID',
  215. 'user_id' => '用户ID',
  216. 'username' => '真实姓名',
  217. 'nickname' => '用户昵称',
  218. 'user_mobile' => '用户手机号',
  219. 'order_no' => '订单编号',
  220. 'out_trade_no' => '外部交易号',
  221. 'mobile' => '收货人的手机号码',
  222. 'detail_address' => '收货人地址全称',
  223. 'receiver_name' => '收货人姓名',
  224. 'province' => '收货人省份',
  225. 'city' => '收货人城市',
  226. 'area' => '收货人地区/街道',
  227. 'town' => '收货人乡/镇',
  228. // 'region_name' => '地区名称(省市区[乡/镇]',
  229. 'address' => '详细地址',
  230. 'goods_name' => '商品名', //detail
  231. 'goods_attr_name' => '规格', //detail
  232. 'num' => '购买数量', //detail
  233. 'cost_price' => '商品成本单价', //detail
  234. 'cost_total_price' => '商品成本总价', //detail
  235. 'original_goods_price' => '商品原本总价', //detail
  236. 'goods_price' => '商品优惠后总价', //detail
  237. 'shipping_money' => '订单运费',
  238. 'created_at' => '下单时间',
  239. 'payment_type' => '支付方式', //-
  240. 'order_type' => '订单情况', //-
  241. 'order_status' => '订单状态', //-
  242. 'pay_status' => '订单付款状态', //-
  243. 'pay_time' => '订单付款时间',
  244. 'shipping_status' => '订单配送状态', //- detail
  245. 'consign_time' => '卖家发货时间', //
  246. 'sign_time' => '买家签收时间',
  247. 'remark' => '用户订单备注',
  248. 'seller_remark' => '商家订单备注',
  249. 'pay_money' => '订单实付金额'
  250. ];
  251. if ($field === null) return $fields;
  252. $temp = [];
  253. foreach ($field as $val) {
  254. if (isset($fields[$val])) $temp[$val] = $fields[$val];
  255. }
  256. return $temp;
  257. }
  258. public function getBase_user()
  259. {
  260. return $this->hasOne(User::class, ['id' => 'user_id'])->select(['id', 'username', 'nickname', 'avatar_url', 'mobile']);
  261. }
  262. public function getStore()
  263. {
  264. return $this->hasOne(Store::class, ['id' => 'store_id']);
  265. }
  266. public function getDetail()
  267. {
  268. return $this->hasMany(StoreOrderDetail::class, ['order_id' => 'id']);
  269. }
  270. public function getExpress()
  271. {
  272. return $this->hasMany(OrderExpress::class, ['order_id' => 'id']);
  273. }
  274. public function getExpress_log()
  275. {
  276. return $this->hasMany(OrderExpressLog::class, ['order_id' => 'id']);
  277. }
  278. public function getReserve()
  279. {
  280. return $this->hasOne(StoreOrderReserve::class, ['order_id' => 'id']);
  281. }
  282. public function beforeSave($insert)
  283. {
  284. // 未支付/未付款
  285. if ($this->isNewRecord || $this->order_status == OrderStatusEnum::NOT_PAY) {
  286. // 支付金额为产品金额
  287. $this->pay_money = $this->goods_price;
  288. // 实付增加运费
  289. $this->pay_money += $this->shipping_money;
  290. }
  291. // var_dump($this->id, $this->isNewRecord, $this->order_status, $this->oldAttributes['order_status']);
  292. // 修改订单商品状态
  293. if (!$this->isNewRecord && isset($this->order_status)&&isset($this->oldAttributes['order_status'])&&
  294. $this->order_status != $this->oldAttributes['order_status']) {
  295. StoreOrderDetail::updateAll(
  296. ['order_status' => $this->order_status],
  297. [ 'order_status' => $this->oldAttributes['order_status'],'order_id' => $this->id]
  298. );
  299. }
  300. return parent::beforeSave($insert);
  301. }
  302. public static function createOrder($form)
  303. {
  304. $stock_locks = [];
  305. try {
  306. if (Order::isStopOrder($form['mall_id'])) throw new Exception('站点维护中,暂时无法下单');
  307. $group_order_goods = $form['group_order_goods'];
  308. $give_data = $form['marketing']['give']??[];
  309. $trans = Yii::$app->db->beginTransaction();
  310. $attr = [];
  311. $order_trade_info = [];
  312. $order_ids = [];
  313. $order_nos = [];
  314. $total_amount = 0;
  315. $data = is_array($form->data) ? $form->data : json_decode($form->data, true);
  316. $tmp_goods_ids = [];
  317. foreach ($group_order_goods as $mch_order) {
  318. $total_amount = 0;
  319. $mch_order_info = $mch_order['mch_order_info'];
  320. // 如果是预约订单且是到店服务
  321. if ($form->type == 'reserve_now' && $form->data['service_type'] == 2) {
  322. // 替换收货地址
  323. $mch_order_info['province'] = $mch_order_info['store']['province_id'];
  324. $mch_order_info['city'] = $mch_order_info['store']['city_id'];
  325. $mch_order_info['area'] = $mch_order_info['store']['district_id'];
  326. $mch_order_info['address'] = $mch_order_info['store']['address'];
  327. $mch_order_info['region_name'] = "";
  328. $mch_order_info['receiver_name'] = $mch_order_info['store']['store_name'];
  329. $mch_order_info['mobile'] = $mch_order_info['store']['shop_mobile'];
  330. $mch_order_info['clerk_code'] = OrderReserve::getClerkCode($mch_order['mall_id'],ClerkEnum::RESERVATION_SERVICE_CLERK_CODE_PRE);
  331. }else{
  332. if ($form->data['shipping_type'] == 2) {
  333. $mch_order_info['clerk_code'] = self::getClerkCode($mch_order_info['mall_id']);
  334. }
  335. }
  336. $order = new StoreOrder();
  337. $order->loadDefaultValues();
  338. $order->load($mch_order_info, '');
  339. $order->order_status = OrderStatusEnum::NOT_PAY;
  340. empty($order->order_no) && $order->order_no = StringHelper::generateOrderNo('st');
  341. $res = $order->save();
  342. if ($res === false) throw new \Exception($order->getErrorMessage());
  343. $main_order = new Order();
  344. $main_order->loadDefaultValues();
  345. $mch_order_info['marketing_type'] = AddonsEnum::ADDONS_NAME_STORE;
  346. $mch_order_info['marketing_id'] = $order->id;
  347. $main_order->load($mch_order_info, '');
  348. $main_order->order_status = OrderStatusEnum::NOT_PAY;
  349. $main_order->order_no = $order->order_no;
  350. $main_order->order_source = $order->order_source == OrderSourceEnum::SOURCE_RESERVE ? OrderSourceEnum::SOURCE_STORE_RESERVE : AddonsEnum::ADDONS_NAME_STORE;
  351. if ($order->supplier_type == StoreEnum::SELF_MALL_WUZHOU && MallAddons::isInstall($mch_order_info['mall_id'], AddonsEnum::ADDONS_NAME_WUZHOU_CHAIN)) {
  352. // 如果供应链是五洲,则订单来源改为五洲
  353. $main_order->order_source = AddonsEnum::ADDONS_NAME_WUZHOU_CHAIN;
  354. }
  355. $res = $main_order->save();
  356. if ($res === false) throw new \Exception($main_order->getErrorMessage());
  357. $res = StoreOrderGive::setData($give_data,$order->id,$order->store_id,$order->mall_id);
  358. if($res === false) throw new Exception(StoreOrderGive::getStaticError());
  359. //赊账
  360. if(!empty($data['is_use_credit'])&&!empty($mch_order_info['credit_money'])){
  361. $params = [
  362. 'mall_id'=>$order['mall_id'],
  363. 'user_id'=>$order['user_id'],
  364. 'order_id'=>$order['id'],
  365. 'store_id'=>$order['store_id'],
  366. 'type'=>1,
  367. 'is_repayment'=>0,
  368. 'down_payments'=>bcsub($order['pay_money'],$mch_order_info['credit_money'],2),
  369. 'credit_money'=>$mch_order_info['credit_money'],
  370. 'extra'=>!empty($mch_order_info['order_extra'])? json_encode($mch_order_info['order_extra']):json_encode([]),
  371. ];
  372. $res = StoreOrderCredit::setData($params);
  373. if ($res === false) throw new \Exception(StoreOrderCredit::getStaticError());
  374. $total_amount+=$params['down_payments'];
  375. }else{
  376. $total_amount+=$order['pay_money'];
  377. }
  378. $order_id = $order->id;
  379. $main_order_id = $main_order->id;
  380. $order_ids[] = $order->id;
  381. $order_nos[] = $order->order_no;
  382. // 总商品库存维护
  383. $goods_stock_arr = [];
  384. // 遍历商户商品
  385. $goods_ids = array_keys($mch_order['goods']);
  386. array_push($tmp_goods_ids, ...$goods_ids);
  387. $deduct_score = 0;
  388. $score_give_data = [];
  389. $score_give_setting = \Yii::$app->services->setting->addons->get($order['mall_id'], StoreEnum::ADDONS_NAME, 'scoreGive.score_give_setting');
  390. if(!empty($score_give_setting)){
  391. $score_give_setting = json_decode($score_give_setting,true);
  392. }
  393. $bear = $score_give_setting['bear']??-1;
  394. $deduct_score_arr = [];
  395. foreach ($mch_order['goods'] as $goods_id => $goods) {
  396. !isset($goods_name) && $goods_name = $goods['goods_name'];
  397. foreach ($goods['goods_details'] as $goods_detail) {
  398. $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GOODS_ATTR, $goods_detail['goods_attr_id']);
  399. $identification = uniqid();
  400. // if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new \Exception('当前访问人数过多');
  401. $stock_locks[$lock_key] = $identification;
  402. //操作商品库存-减
  403. StoreGoodsAttr::handleStock($goods_detail['goods_attr_id'], $goods_detail['num'] * -1);
  404. if (!isset($goods_stock_arr[$goods_id])) {
  405. $goods_stock_arr[$goods_id] = $goods_detail['num'];
  406. } else {
  407. $goods_stock_arr[$goods_id] += $goods_detail['num'];
  408. }
  409. // 订单详情
  410. $main_order_detail = new OrderDetail();
  411. $main_order_detail->loadDefaultValues();
  412. $main_order_detail->load($goods_detail, '');
  413. $main_order_detail->store_id = $main_order->store_id;
  414. $main_order_detail->order_id = $main_order_id;
  415. if($goods_detail['supplier_type'] == StoreEnum::SELF_MALL_WUZHOU&& isset($goods_detail['mall_goods_id'])){
  416. //$main_order_detail->goods_id = $goods_detail['mall_goods_id'] > 0 ? $goods_detail['mall_goods_id'] : $goods_detail['goods_id'];
  417. //$main_order_detail->goods_attr_id = $goods_detail['mall_attr_id'] > 0 ? $goods_detail['mall_attr_id'] : $goods_detail['goods_attr_id'];
  418. $main_order_detail->order_source = AddonsEnum::ADDONS_NAME_WUZHOU_CHAIN;
  419. }
  420. $res = $main_order_detail->save();
  421. $order_detail = new StoreOrderDetail();
  422. $order_detail->loadDefaultValues();
  423. $order_detail->load($goods_detail, '');
  424. $order_detail->order_id = $order_id;
  425. $order_detail->main_order_detail_id = $main_order_detail->id;
  426. $res = $order_detail->save();
  427. if ($res === false) throw new \Exception($order_detail->getErrorMessage());
  428. if ($res === false) throw new \Exception($main_order_detail->getErrorMessage());
  429. $attr[$goods_detail['goods_attr_id']] = $goods_detail['num'];
  430. if (!empty($goods_detail['marketing'])) {
  431. if(empty($goods_detail['marketing']['give_score'])){
  432. $goods_detail['marketing']['give_score'] = 0;
  433. }
  434. if($bear==1 && !empty($goods_detail['marketing']['give_score'])){
  435. //门店主承担积分赠送
  436. $score_give_data[$order_detail['store_id']][$order_detail->id] = $goods_detail['marketing']['give_score'];
  437. }
  438. $res = StoreOrderMarketing::setData($goods_detail['marketing'],$order_detail->id,$order_detail->store_id,$order_detail->mall_id);
  439. if($res === false) throw new Exception(StoreOrderMarketing::getStaticError());
  440. if($goods_detail['marketing']['deduct_score']>0){
  441. $deduct_score_arr[] = [
  442. 'order_detail_id'=> $order_detail->id,
  443. 'deduct_score'=> $goods_detail['marketing']['deduct_score'],
  444. ];
  445. }
  446. }
  447. }
  448. }
  449. if(!empty($deduct_score_arr)){
  450. self::subUserScore($order,$deduct_score_arr);
  451. }
  452. if($score_give_data){
  453. self::subStoreUserScore($order,$score_give_data);
  454. }
  455. if (!empty($data['user_coupon_ids'])) {
  456. $user_coupon_id = $data['user_coupon_ids'];
  457. $res =StoreCouponUserRelate::updateAll(['is_use' => 1,'updated_at'=>time()], ['id' => $user_coupon_id]);
  458. if ($res === false) throw new \Exception($order->getErrorMessage());
  459. }
  460. $order_trade_info[] = [
  461. 'order_no' => $order->order_no,
  462. 'amount' => $total_amount,
  463. 'title' => StoreOrder::getOrderTitle($order),
  464. 'notify_class' => 'addons\Store\common\logic\notify\Notify',
  465. 'order_type' => 'order',
  466. ];
  467. }
  468. if ($order->order_source === OrderSourceEnum::SOURCE_RESERVE) {
  469. // 预约类型的订单,单独保存信息
  470. $res = StoreOrderReserve::create($order, $form, $main_order_id ?? 0);
  471. if ($res == false) throw new Exception(StoreOrderReserve::getStaticError());
  472. }
  473. $trans->commit();
  474. // LockHelper::batchUlock($stock_locks);
  475. //生成支付流水
  476. $res = \Yii::$app->services->pay->createTrade($form['mall_id'], $form['user_id'], $order_trade_info);
  477. if ($res == false) throw new \Exception('生成支付流水失败');
  478. StoreOrder::updateAll(['out_trade_no' => $res['trade_no']], ['id' => $order_ids]);
  479. Order::updateAll(['out_trade_no' => $res['trade_no']], ['order_no' => $order_nos]);
  480. // 触发订单添加事件,事务提交完成后触发
  481. $event = new OrderCreateEvent($form['mall_id']);
  482. Yii::$app->services->events->dispatch($event, ['order_ids' => $order_ids], $event->listeners);
  483. //删除购物车
  484. if ($form->type == 'cart') StoreCart::decreaseNumb(['user_id' => $form->user_id, 'list' => $attr]);
  485. $res['order_ids'] = implode(',', $order_ids);
  486. $arr['transaction'] = $res;
  487. // 有可能需要跳转到指定页面
  488. $arr['is_jump'] = StatusEnum::DISABLED;
  489. if (count($tmp_goods_ids) == 1 && MallAddons::isInstall($order->mall_id, AddonsEnum::ADDONS_NAME_PAY_SUCCESS_JUMP)) {
  490. // 判断是否有开启
  491. $jump_url_config = \Yii::$app->services->setting->addons->get($order->mall_id,
  492. AddonsEnum::ADDONS_NAME_PAY_SUCCESS_JUMP, 'basic');
  493. // 两个都开启的情况下
  494. if (intval($jump_url_config['is_enable_jump']) && intval($jump_url_config['is_enable'])) {
  495. $jump_url = (new JumpUrlService())->getJumpUrl($order->mall_id, $tmp_goods_ids[0], StoreEnum::ADDONS_NAME);
  496. if (!empty($jump_url)) {
  497. $arr['pay_success_page'] = Json::encode(['route' => $jump_url, 'open_type' => 'page', 'params' => []]);
  498. $arr['is_jump'] = StatusEnum::ENABLED;
  499. }
  500. }
  501. }
  502. // 判断是否有安装抽奖插件
  503. if (MallAddons::isInstall($order->mall_id, AddonsEnum::ADDONS_NAME_SHOPPING_LOTTERY)) {
  504. $pay_success_page = LotteryHelper::getJumpUrl($order->mall_id, $res['trade_no'], StatusEnum::ENABLED);
  505. if (!empty($pay_success_page)) {
  506. $arr['pay_success_page'] = $pay_success_page;
  507. $arr['is_jump'] = StatusEnum::ENABLED;
  508. }
  509. }
  510. if (empty($arr['pay_success_page'])) {
  511. $arr['pay_success_page'] = Yii::$app->services->setting->addons->get($order->mall_id, StoreEnum::ADDONS_NAME, 'payment.pay_after_link');// 支付成功后跳转的地址
  512. if (!empty($arr['pay_success_page'])) {
  513. $arr['is_jump'] = StatusEnum::ENABLED;
  514. }
  515. }
  516. // $arr['pay_success_page'] = Yii::$app->services->setting->mall->get($form['mall_id'], 'order.pay_after_link'); // 支付成功后跳转的地址
  517. $payment_expire_time = Yii::$app->services->setting->mall->get($form['mall_id'], 'order.payment_expire_time');
  518. $arr['surplus_second'] = 30 * 60; //剩余秒数
  519. if ($payment_expire_time) {
  520. $arr['surplus_second'] = intval($payment_expire_time) * 60; //剩余秒数
  521. }
  522. $arr['main_order_id'] = $main_order_id ?? 0;
  523. return $arr;
  524. } catch (\Exception $e) {
  525. // LockHelper::batchUlock($stock_locks);
  526. if (isset($trans)) $trans->rollback();
  527. self::$static_error = $e->getMessage();
  528. return false;
  529. }
  530. }
  531. /**
  532. * 积分抵扣-扣除下单这的积分
  533. * @param $order
  534. * @param $deduct_score_arr
  535. * @return void
  536. * @throws Exception
  537. */
  538. protected static function subUserScore($order,$deduct_score_arr)
  539. {
  540. foreach ($deduct_score_arr as $item){
  541. $deduct_score = $item['deduct_score'];
  542. $desc = '用户('.$order['user_id'].'),下单('.$order['id'].')抵扣积分,数量:'.$deduct_score;
  543. $data = [
  544. 'mall_id' => $order['mall_id'],
  545. 'user_id' => $order['user_id'],
  546. 'is_frozen' => false,
  547. 'wallet_type' => 'score',
  548. 'money' => -$deduct_score,
  549. 'desc' => $desc,
  550. 'source_table' => StoreOrderDetail::tableName(),
  551. 'source_table_id' => $item['order_detail_id'],
  552. 'from_type' => UserWalletEnum::CONSUME,
  553. 'capital_type' => 'consume_store_order',
  554. 'order_no' => $order['order_no'],
  555. ];
  556. $res = UserWalletService::handle(0, $data);
  557. if ($res == false) throw new \Exception('抵扣积分失败');
  558. }
  559. }
  560. /**
  561. * 订单关闭-退回积分抵扣
  562. * @param $order
  563. * @param $deduct_score
  564. * @return void
  565. * @throws Exception
  566. */
  567. protected static function backUserScoreDeduct($order)
  568. {
  569. $order_detail_ids = array_column($order['detail'],'id');
  570. $score_log_list = ScoreLog::lists([
  571. 'where'=>[
  572. ['user_id'=>$order['user_id']],
  573. ['change_type'=>'sub'],
  574. ['source_table'=>StoreOrderDetail::tableName()],
  575. ['source_table_id'=>$order_detail_ids],
  576. ['from_type' => AddonsEnum::ADDONS_NAME_STORE],
  577. ['capital_type'=>'consume_store_order'],
  578. ]
  579. ]);
  580. if(!empty($score_log_list)){
  581. $insert_wallet = [];
  582. foreach ($score_log_list as $item){
  583. $deduct_score = $item['change_num'];
  584. $desc = '订单关闭,退回,用户('.$order['user_id'].'),下单('.$order['id'].')的抵扣积分,数量:'.$deduct_score;
  585. $insert_wallet[] =
  586. [
  587. 'mall_id' => $item['mall_id'],
  588. 'user_id' => $item['user_id'],
  589. 'is_frozen' => false,
  590. 'wallet_type' => 'score',
  591. 'money' => $deduct_score,
  592. 'desc' => $desc,
  593. 'source_table' => $item['source_table'],
  594. 'source_table_id' => $item['source_table_id'],
  595. 'from_type' => UserWalletEnum::CONSUME,
  596. 'capital_type' => 'consume_store_order',
  597. 'order_no' => $order['order_no'],
  598. ];
  599. }
  600. if($insert_wallet){
  601. $res = UserWalletService::batchHandleByQueue($insert_wallet);
  602. }
  603. }
  604. }
  605. /**
  606. * 积分赠送-扣除门店主积分
  607. * @param $mall_id
  608. * @param $score_give_data
  609. * @return void
  610. * @throws Exception
  611. */
  612. protected static function subStoreUserScore($order,$score_give_data)
  613. {
  614. $prize_name = '积分赠送';
  615. $store_ids = array_keys($score_give_data);
  616. $store_list = Store::lists(['where'=>[['id'=>$store_ids]],'index'=>'id','select'=>'id,user_id']);
  617. foreach ($score_give_data as $store_id=>$item) {
  618. $store_user_id = $store_list[$store_id]['user_id'] ?? 0;
  619. if (empty($store_user_id)) {
  620. continue;
  621. }
  622. foreach ($item as $order_detail_id => $score) {
  623. try {
  624. if ($score > 0) {
  625. $desc = '门店承担门店订单(' . $order['id'] . ')奖励,奖励类型:' . $prize_name . ',积分:' . $score;
  626. $data = [
  627. 'mall_id' => $order['mall_id'],
  628. 'user_id' => $store_user_id,
  629. 'is_frozen' => false,
  630. 'wallet_type' => 'score',
  631. 'money' => -$score,
  632. 'desc' => $desc,
  633. 'source_table' => StoreOrderDetail::tableName(),
  634. 'source_table_id' => $order_detail_id,
  635. 'from_type' => AddonsEnum::ADDONS_NAME_STORE,
  636. 'capital_type' => UserWalletEnum::CONSUME_ORDER_GIVE,
  637. 'order_no' => $order['order_no'],
  638. ];
  639. $res = UserWalletService::handle(0, $data);
  640. if ($res == false) throw new \Exception('积分赠送扣除门店主积分失败');
  641. }
  642. } catch (Exception $e) {
  643. $update = ['give_score' => 0];
  644. $condition = ['order_detail_id' => $order_detail_id];
  645. StoreOrderMarketing::updateAll($update, $condition);
  646. Yii::error('order_detail_id:'.$order_detail_id.$e->getMessage());
  647. }
  648. }
  649. }
  650. }
  651. /**
  652. * 订单关闭-退回积分赠送给门店主
  653. * @param $order
  654. * @return true|void
  655. * @throws Exception
  656. */
  657. protected static function backStoreUserScore($order)
  658. {
  659. $store = Store::findOne(['id'=>$order['store_id']]);
  660. $store_user_id = $store['user_id']??0;
  661. if($store_user_id==0){
  662. return true;
  663. }
  664. $order_detail_ids = array_column($order['detail'],'id');
  665. $score_log_list = ScoreLog::lists([
  666. 'where'=>[
  667. ['user_id'=>$store_user_id],
  668. ['change_type'=>'sub'],
  669. ['source_table'=>StoreOrderDetail::tableName()],
  670. ['source_table_id'=>$order_detail_ids],
  671. ['from_type' => AddonsEnum::ADDONS_NAME_STORE],
  672. ['capital_type'=>UserWalletEnum::CONSUME_ORDER_GIVE],
  673. ]
  674. ]);
  675. if(!empty($score_log_list)){
  676. $prize_name = '订单关闭-退回积分赠送';
  677. $insert_wallet = [];
  678. foreach ($score_log_list as $item){
  679. $order_detail_id = $item['order_detail_id'];
  680. $score = $item['change_num'];
  681. $desc = '订单关闭,退回积分赠送扣除门店主的积分,门店订单(' . $order_detail_id . ')奖励,奖励类型:' . $prize_name . ',积分:' . $score;
  682. $insert_wallet[] = [
  683. 'mall_id' => $item['mall_id'],
  684. 'user_id' => $item['user_id'],
  685. 'is_frozen' => false,
  686. 'wallet_type' => 'score',
  687. 'money' => $score,
  688. 'desc' => $desc,
  689. 'source_table' => StoreOrderDetail::tableName(),
  690. 'source_table_id' => $order_detail_id,
  691. 'from_type' => AddonsEnum::ADDONS_NAME_STORE,
  692. 'capital_type' => UserWalletEnum::CONSUME_ORDER_GIVE,
  693. 'order_no' => $order['order_no'],
  694. ];
  695. }
  696. $res = UserWalletService::batchHandleByQueue($insert_wallet);
  697. }
  698. }
  699. public function getDeductScoreInsertWallet($mall_id,$user_id,$order_id,$order_detail_ids,$source_table,$from_type,$capital_type){
  700. $list = StoreOrderMarketing::findAll(['order_detail_id'=>$order_detail_ids]);
  701. $deduct_score = 0;
  702. foreach ($list as $value){
  703. $deduct_score+=$value['deduct_score'];
  704. }
  705. $desc = '用户('.$user_id.'),下单('.$order_id.')抵扣积分,数量:'.$deduct_score;
  706. if($deduct_score>0){
  707. return ['mall_id' => $mall_id, 'user_id' => $user_id,
  708. 'is_frozen' => false, 'wallet_type' => 'score', 'money' => -$deduct_score,
  709. 'desc' => $desc,
  710. 'source_table' => $source_table,
  711. 'source_table_id' => $order_id,
  712. 'from_type' => $from_type,
  713. 'capital_type' => $capital_type,
  714. ];
  715. }else{
  716. return [];
  717. }
  718. }
  719. /**
  720. * 获取订单标题
  721. * @param StoreOrder $order
  722. * @return string
  723. */
  724. public static function getOrderTitle($order)
  725. {
  726. $details = $order->getDetail()->all();
  727. if (empty($details) || !is_array($details) || count($details) < 1) {
  728. return '';
  729. }
  730. $titles = [];
  731. foreach ($details as $detail) {
  732. $titles[] = $detail->goods_name;
  733. }
  734. $title = implode(';', $titles);
  735. return mb_strlen($title) > 32 ? mb_substr($title, 0, 32) : $title;
  736. }
  737. public static function getClerkCode($mall_id)
  738. {
  739. while (true) {
  740. $clerk_code = ClerkEnum::getCode(ClerkEnum::O2O_SELF_PICKUP_ORDERS_CLERK_CODE_PRE);
  741. $res = Order::findOne(['mall_id' => $mall_id, 'clerk_code' => $clerk_code, 'status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]);
  742. if (empty($res)) break;
  743. }
  744. if (empty($clerk_code)) throw new \Exception('核销码生成失败');
  745. return $clerk_code;
  746. }
  747. /**
  748. * 订单备注
  749. * @Author bing
  750. * @DateTime 2021-09-14 15:43:18
  751. * @copyright: Copyright (c) 2020 广东七件事集团
  752. * @param [type] $params
  753. * @return object|bool
  754. */
  755. public static function remark($params)
  756. {
  757. try {
  758. $model = self::findOne(['mall_id' => $params['mall_id'], 'id' => $params['id'], 'store_id' => $params['store_id'], 'status' => [StatusEnum::ENABLED]]);
  759. if (empty($model)) throw new \Exception('订单不存在或已删除');
  760. $model->remark = $params['remark'] ?? $model->remark;
  761. $model->seller_remark = $params['seller_remark'] ?? $model->seller_remark;
  762. if (!$model->save()) throw new \Exception($model->getErrorMessage());
  763. $order = Order::findOne(['order_no'=>$model['order_no']]);
  764. $order->remark = $model->remark;
  765. $order->seller_remark = $model->seller_remark;
  766. if (!$order->save()) throw new \Exception($order->getErrorMessage());
  767. return $model;
  768. } catch (\Exception $e) {
  769. if (isset($trans)) $trans->rollback();
  770. self::$static_error = $e->getMessage();
  771. return false;
  772. }
  773. }
  774. /**
  775. * 管理员订单支付
  776. * @Author bing
  777. * @DateTime 2021-09-10 10:43:57
  778. * @copyright: Copyright (c) 2020 广东七件事集团
  779. * @param StoreOrder $params 参数
  780. * @param [type] $payment_type 支付方式
  781. * @return boolean|object
  782. */
  783. public static function pay($params, $peyment_type)
  784. {
  785. try {
  786. $trans = Yii::$app->db->beginTransaction();
  787. $model = self::findOne(['id' => $params['id'], 'status' => [StatusEnum::ENABLED]]);
  788. if (empty($model)) throw new Exception('订单不存在或已删除');
  789. if ($model->order_status != OrderStatusEnum::NOT_PAY) throw new Exception('订单已经被处理,无法进行支付');
  790. if ($model->pay_status == StatusEnum::ENABLED) throw new Exception('订单已支付,请不要重复支付');
  791. if($model->shipping_type==ShippingTypeEnum::PICKUP){
  792. $model->order_status = OrderStatusEnum::TAKE;
  793. }else{
  794. $model->order_status = OrderStatusEnum::PAY;
  795. }
  796. $model->payment_type = $peyment_type;
  797. $model->pay_status = StatusEnum::ENABLED;
  798. $model->pay_time = time();
  799. if ($model->order_source === OrderSourceEnum::SOURCE_RESERVE) {
  800. // 预约商品支付后,改成发货状态
  801. // 平台订单
  802. $reserveOrder = StoreOrderReserve::findOne(['order_id' => $model->id]);
  803. if ($reserveOrder->reserve_type == StatusEnum::DISABLED) { // 家政才需要修改为发货状态
  804. // 预约商品支付后,改成发货状态
  805. $model->shipping_status = StatusEnum::ENABLED; // 全部发货状态改为已发货
  806. // 如果是技师,那么就为已支付
  807. $model->order_status = OrderStatusEnum::SHIPMENTS;
  808. $model->consign_time = time();
  809. }
  810. StoreOrderReserve::syncOrderStatus($model);
  811. }
  812. $res = $model->save();
  813. if ($res === false) throw new Exception('修改订单失败:' . $model->getErrorMessage());
  814. $main_order_model = Order::findOne(['order_no' => $model['order_no'], 'status' => [StatusEnum::ENABLED]]);
  815. if($main_order_model){
  816. $main_order_model->order_status = $model->order_status;
  817. $main_order_model->payment_type = $peyment_type;
  818. $main_order_model->pay_status = StatusEnum::ENABLED;
  819. $main_order_model->pay_time = time();
  820. $main_order_model->out_trade_no = $model->out_trade_no;
  821. // 平台订单
  822. if (empty($reserveOrder)) $reserveOrder = StoreOrderReserve::findOne(['order_id' => $model->id]);
  823. if ($model->order_source === OrderSourceEnum::SOURCE_RESERVE && $reserveOrder->reserve_type == StatusEnum::DISABLED) {
  824. // 预约商品支付后,改成发货状态
  825. $main_order_model->shipping_status = StatusEnum::ENABLED; // 全部发货状态改为已发货
  826. $main_order_model->order_status = OrderStatusEnum::SHIPMENTS;
  827. $main_order_model->consign_time = time();
  828. }
  829. $res = $main_order_model->save();
  830. if ($res === false) throw new Exception('修改订单失败:' . $main_order_model->getErrorMessage());
  831. }
  832. // 增加销量
  833. $order_detail = $model->detail;
  834. $sale_num_goods = [];
  835. foreach ($order_detail as $product) {
  836. if (isset($sale_num_goods[$product['goods_id']])) {
  837. $sale_num_goods[$product['goods_id']] += $product['num'];
  838. } else {
  839. $sale_num_goods[$product['goods_id']] = $product['num'];
  840. }
  841. }
  842. foreach ($sale_num_goods as $goods_id => $sale_num) {
  843. $goods = StoreGoods::findOne($goods_id);
  844. $goods->sales_num += $sale_num;
  845. $goods->save();
  846. }
  847. $order_no = $model['order_no'];
  848. $payment_trade_order = PaymentTradeOrder::findOne(['order_no'=>$order_no,'order_type'=>'order','is_pay'=>1]);
  849. $order_credit = StoreOrderCredit::findOne(['order_id'=>$params['id'],'type'=>1]);
  850. if(!empty($order_credit)){
  851. $field = ['pay_time'=>time()];
  852. if($payment_trade_order['total_fee']>$order_credit['down_payments']){
  853. //有赊账,但没有立即支付,属于第2次付款
  854. $field['is_repayment'] = 1;
  855. $field['down_payments'] = $payment_trade_order['total_fee'];
  856. $field['credit_money'] = 0;
  857. }
  858. StoreOrderCredit::updateAll($field,['order_id'=>$params['id'],'type'=>1]);
  859. }
  860. $trans->commit();
  861. // 触发订单支付事件,事务提交完成后触发
  862. $number = 0;
  863. $addons_arr = [AddonsEnum::ADDONS_NAME_AGENT,AddonsEnum::ADDONS_NAME_DISTRIBUTION,AddonsEnum::ADDONS_NAME_AREA,AddonsEnum::ADDONS_NAME_BOSS,'StoreBoss'];
  864. foreach ($addons_arr as $addons){
  865. if(MallAddons::isInstall($model['mall_id'],$addons)){
  866. $number++;
  867. }
  868. }
  869. if($number){
  870. \Yii::$app->services->taskCounter->set('o2o:order_id:' . $model['id'])->incr($number);
  871. }else{
  872. $event = new ComputeCommissionEvent($model['mall_id']);
  873. $data = [];
  874. $data['order_id'] = $model['id'];
  875. $data['operator_id'] = $params['operator_id'] ?? 0;
  876. $data['operator_name'] = $params['operator_name'] ?? '';
  877. $data['commission_arr'] = [];
  878. //此处事件 不调用
  879. //Yii::$app->services->events->dispatch($event, $data, $event->listeners);
  880. }
  881. $event = new OrderPaidEvent($model['mall_id']);
  882. $order['id'] = $model['id'];
  883. $order['operator_id'] = $params['operator_id'] ?? 0;
  884. $order['operator_name'] = $params['operator_name'] ?? '';
  885. $order['mall_order_id'] = $main_order_model->id ?? 0;
  886. Yii::$app->services->events->dispatch($event, $order, $event->listeners);
  887. return $model;
  888. } catch (Exception $e) {
  889. if (isset($trans)) $trans->rollback();
  890. self::$static_error = $e->getMessage();
  891. return false;
  892. }
  893. }
  894. /**
  895. * @desc:提交订单评价
  896. * @Author: hua
  897. * @Date: 2021/10/19
  898. * @Time: 18:28
  899. * @Copyright: copyright (c) 2021 广东七件事集团
  900. * @param $params
  901. * @return bool
  902. */
  903. public static function postComments($params)
  904. {
  905. $t = Yii::$app->db->beginTransaction();
  906. try {
  907. $store_order = StoreOrder::findOne(['id' => $params['order_id']]);
  908. if (empty($store_order)) throw new Exception('订单不存在');
  909. $order_comments = OrderComments::findOne(['store_id' => $store_order['store_id'], 'order_id' => $params['order_id']]);
  910. if (!empty($order_comments)) throw new Exception('订单已评价,无需再次评价');
  911. foreach ($params['comment_data'] as $item) {
  912. $item['store_id'] = $store_order->store_id;
  913. $item['mall_id'] = $store_order->mall_id;
  914. $item['user_id'] = $store_order->user_id;
  915. $item['order_id'] = $store_order['id'];
  916. $res = self::saveComments($item);
  917. if ($res === false) throw new Exception(OrderComments::getStaticError());
  918. }
  919. $store_order->order_status = OrderStatusEnum::ACCOMPLISH;
  920. $store_order->finish_time = time();
  921. $store_order->is_comment = 1;
  922. $store_order->save();
  923. $order = Order::findOne(['order_no' => $store_order['order_no']]);
  924. $params['order_id'] = $order['id'];
  925. Order::postComments($params);
  926. $t->commit();
  927. // 订单完成触发事件
  928. $user = User::getOne([['id'=>$order->user_id]],true,[],false,'nickname');
  929. $event = new OrderFinishEvent($order->mall_id);
  930. $data['id'] = $order->id;
  931. $data['order_no'] = $store_order['order_no'];
  932. $data['operator_id'] = $order->user_id;
  933. $data['operator_name'] = $user['nickname'];
  934. Yii::$app->services->events->dispatch($event, $data, $event->listeners);
  935. return true;
  936. } catch (Exception $e) {
  937. $t->rollBack();
  938. self::$static_error = $e->getMessage();
  939. return false;
  940. }
  941. }
  942. //
  943. protected static function saveComments($params)
  944. {
  945. try {
  946. if (!empty($params['id'])) {
  947. $model = OrderComments::findOne(['id' => $params['id'], 'status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]);
  948. if (empty($model)) throw new Exception('服务不存在或已删除');
  949. } else {
  950. $model = new OrderComments();
  951. $model->loadDefaultValues();
  952. }
  953. if (isset($params['pic_url'])) $params['pic_url'] = json_encode($params['pic_url']); //后台虚拟
  954. if (isset($params['pic_list'])) $params['pic_url'] = $params['pic_list']; //前端真实用户
  955. if (!empty($params['virtual_time'])) $params['virtual_time'] = strtotime($params['virtual_time']);
  956. if (!$model->load($params, '') || !$model->save()) throw new Exception($model->getErrorMessage());
  957. $res = StoreOrderDetail::setData(['id' => $params['order_detail_id'], 'mall_id' => $params['mall_id'], 'is_evaluate' => 1]);
  958. if (!$res) throw new Exception(OrderDetail::getStaticError());
  959. return $model;
  960. } catch (Exception $e) {
  961. self::$static_error = $e->getMessage();
  962. return false;
  963. }
  964. }
  965. /**
  966. * @name:
  967. * @msg: 拼装搜索参数
  968. * @param {*} $mall_id
  969. * @param {*} $search
  970. * @return {*}
  971. */
  972. public static function searchParams($mall_id, $search)
  973. {
  974. // 查询参数
  975. $isReserve = $search['is_reserve'];
  976. $where[] = ['=', 'mall_id', $mall_id];
  977. $where[] = ['>=', 'status', StatusEnum::DISABLED];
  978. if ($isReserve) {
  979. $where[] = ['=', 'order_source', OrderSourceEnum::SOURCE_RESERVE];
  980. } else {
  981. $where[] = ['not in', 'order_source', [OrderSourceEnum::SOURCE_SELF_MALL, OrderSourceEnum::SOURCE_RESERVE]];
  982. }
  983. if (isset($search['order_id'])) $where[] = ['in', 'id', explode(',', $search['order_id'])];
  984. ($search['payment_type'] ?? false) && $where[] = ['=', 'payment_type', $search['payment_type']];
  985. ($search['shipping_type'] ?? false) && $where[] = ['=', 'shipping_type', $search['shipping_type']];
  986. if (isset($search['order_status']) && $search['order_status'] != 999) {
  987. if ($isReserve && $search['order_status'] == OrderStatusEnum::SING) { // 以前端栏目配置服务中即待验收其状态包括已提货
  988. $where[] = ['in', 'order_status', [OrderStatusEnum::SING, OrderStatusEnum::TAKE_FINISH]];
  989. } else {
  990. $where[] = ['=', 'order_status', $search['order_status']];
  991. }
  992. }
  993. ($search['order_no'] ?? false) && $where[] = ['=', 'order_no', $search['order_no']];
  994. ($search['start'] ?? false) && $where[] = ['>=', 'created_at', strtotime($search['start'])];
  995. ($search['end'] ?? false) && $where[] = ['<=', 'created_at', strtotime($search['end'])];
  996. if ($search['type_value'] ?? false) {
  997. switch ($search['type']) {
  998. case 'mobile':
  999. $uids = User::find()->select('id')->where(['like', 'mobile', $search['type_value'] . '%', false])->column();
  1000. !empty($uids) && $where[] = ['in', 'user_id', $uids];
  1001. break;
  1002. case 'user_id':
  1003. $where[] = ['in', 'user_id', $search['type_value']];
  1004. break;
  1005. case 'consignee':
  1006. case 'consignee_mobile':
  1007. if ($search['type'] == 'consignee') {
  1008. $where[] = ['like', 'receiver_name', $search['type_value'] . '%', false];
  1009. } else {
  1010. $where[] = ['like', 'mobile', $search['type_value'] . '%', false];
  1011. }
  1012. break;
  1013. default:
  1014. }
  1015. }
  1016. return $where;
  1017. }
  1018. /**
  1019. * @name:
  1020. * @msg: 订单修改价格
  1021. * @param {array} $params
  1022. * @return {*}
  1023. */
  1024. public static function changePrice(array $params)
  1025. {
  1026. try {
  1027. $model = self::findOne(['mall_id' => $params['mall_id'], 'id' => $params['id'], 'status' => [StatusEnum::ENABLED]]);
  1028. if (empty($model)) throw new Exception('订单不存在或已删除');
  1029. $model->shipping_money = $params['shipping_money'];
  1030. $trans = Yii::$app->db->beginTransaction();
  1031. // 修改订单详情调价
  1032. $all_goods_price = OrderDetail::priceAdjustment($params['detail']);
  1033. if ($all_goods_price === false) throw new Exception('调整订单商品价格失败:' . $model->getErrorMessage());
  1034. $model->goods_price = $all_goods_price;
  1035. $res = $model->save();
  1036. if ($res === false) throw new Exception('修改订单运费失败:' . $model->getErrorMessage());
  1037. $trans->commit();
  1038. return $model;
  1039. } catch (Exception $e) {
  1040. if (isset($trans)) $trans->rollback();
  1041. self::$static_error = $e->getMessage();
  1042. return false;
  1043. }
  1044. }
  1045. /**
  1046. * @name:
  1047. * @msg: 关闭订单
  1048. * @param {*} $params
  1049. * @param {*} $force
  1050. * @return {*}
  1051. */
  1052. public static function close($params, $force = false)
  1053. {
  1054. $trans = Yii::$app->db->beginTransaction();
  1055. $stock_locks = [];
  1056. $close_lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GOODS, $params['id']);
  1057. try {
  1058. // 加锁
  1059. $close_identification = uniqid();
  1060. $stock_locks[$close_lock_key] = $close_identification;
  1061. if (!LockHelper::lock($close_lock_key, $close_identification, 30, 60)) throw new \Exception('正在关闭订单');
  1062. $cond = ['mall_id' => $params['mall_id'], 'id' => $params['id'], 'status' => [StatusEnum::ENABLED]];
  1063. isset($params['user_id']) && $cond['user_id'] = $params['user_id'];
  1064. isset($params['store_id']) && $cond['store_id'] = $params['store_id'];
  1065. $model = self::findOne($cond);
  1066. if (empty($model)) throw new Exception('订单不存在或已删除1');
  1067. // 判断订单是否已经被关闭
  1068. if ($model->order_status == OrderStatusEnum::REPEAL) throw new Exception('订单已经关闭');
  1069. // 判断是否是未支付的订单
  1070. if ($force == false && $model->order_status != OrderStatusEnum::NOT_PAY) throw new Exception('订单已经被处理');
  1071. $order = Order::findOne(['order_no'=>$model['order_no']]);
  1072. $model->close_time = time();
  1073. $model->order_status = OrderStatusEnum::REPEAL;
  1074. if (!$model->save()) throw new Exception($model->getErrorMessage());
  1075. if(!empty($order)){
  1076. $order->close_time = $model->close_time;
  1077. $order->order_status = $model->order_status;
  1078. if (!$order->save()) throw new Exception($order->getErrorMessage());
  1079. }
  1080. $goods_attr_arr = array_column($model->detail, 'num', 'goods_attr_id');
  1081. //操作规格库存-回退
  1082. foreach ($goods_attr_arr as $goods_attr_id => $num) {
  1083. $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GOODS_ATTR, $goods_attr_id);
  1084. $identification = uniqid();
  1085. if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new Exception('当前访问人数过多');
  1086. $stock_locks[$lock_key] = $identification;
  1087. //操作商品库存-回退
  1088. StoreGoodsAttr::handleStock($goods_attr_id, $num);
  1089. }
  1090. $trans->commit();
  1091. $store_order_detail_id_arr = array_column($model->detail,'id');
  1092. $store_order = StoreOrder::findOne(['order_no'=>$model['order_no']]);
  1093. $res = StoreOrderMarketing::deductBack($store_order,$store_order_detail_id_arr,$store_order_detail_id_arr,$model['mall_id'],$model['user_id'],'交易关闭返还');
  1094. if ($res == false) throw new Exception(StoreOrderMarketing::getStaticError());
  1095. self::backStoreUserScore($store_order);
  1096. self::backUserScoreDeduct($store_order);
  1097. $res = StoreOrderReserve::updateAll(['order_status' => -4], ['main_order_id' => $order['id']]);
  1098. var_dump($res);
  1099. // 触发订单取消事件
  1100. // 解锁
  1101. LockHelper::batchUlock($stock_locks);
  1102. return $model;
  1103. } catch (Exception $e) {
  1104. $trans->rollback();
  1105. // 解锁
  1106. LockHelper::batchUlock($stock_locks);
  1107. self::$static_error = $e->getMessage();
  1108. return false;
  1109. }
  1110. }
  1111. /**
  1112. * @name:
  1113. * @msg: 删除订单
  1114. * @param {*} $params
  1115. * @return {*}
  1116. */
  1117. public static function del($params)
  1118. {
  1119. try {
  1120. $model = self::findOne(['mall_id' => $params['mall_id'], 'id' => $params['id'], 'status' => [StatusEnum::ENABLED]]);
  1121. if (empty($model)) throw new Exception('订单不存在或已删除');
  1122. if ($model->order_status != OrderStatusEnum::REPEAL) throw new Exception('只允许删除已关闭订单');
  1123. $model->status = StatusEnum::DELETE;
  1124. if (!$model->save()) throw new Exception($model->getErrorMessage());
  1125. $order = Order::findOne(['order_no'=>$model['order_no']]);
  1126. if(!empty($order)){
  1127. $order->status = $model->status;
  1128. if (!$order->save()) throw new Exception($order->getErrorMessage());
  1129. }
  1130. return $model;
  1131. } catch (Exception $e) {
  1132. if (isset($trans)) $trans->rollback();
  1133. self::$static_error = $e->getMessage();
  1134. return false;
  1135. }
  1136. }
  1137. /**
  1138. * @name:
  1139. * @msg: 修改订单收货地址
  1140. * @param {*} $params
  1141. * @return {*}
  1142. */
  1143. public static function changeAddress($params)
  1144. {
  1145. try {
  1146. $model = self::findOne(['mall_id' => $params['mall_id'], 'id' => $params['id'], 'status' => [StatusEnum::ENABLED]]);
  1147. if (empty($model)) throw new Exception('订单不存在或已删除');
  1148. if (!$model->load($params, '') || !$model->save()) throw new \Exception($model->getErrorMessage());
  1149. $order = Order::findOne(['order_no'=>$model['order_no']]);
  1150. $params['id'] = $order['id'];
  1151. Order::changeAddress($params);
  1152. return $model;
  1153. } catch (Exception $e) {
  1154. self::$static_error = $e->getMessage();
  1155. return false;
  1156. }
  1157. }
  1158. /**
  1159. * 发货
  1160. * @Author bing
  1161. * @DateTime 2021-09-16 17:35:05
  1162. * @copyright: Copyright (c) 2020 广东七件事集团
  1163. * @param [type] $params
  1164. * @return void
  1165. */
  1166. public static function delivery($params){
  1167. try{
  1168. $model = self::findOne(['mall_id' => $params['mall_id'], 'id' => $params['id'],'status'=>[StatusEnum::ENABLED]]);
  1169. if(empty($model)) throw new Exception('订单不存在或已删除');
  1170. if ($model->order_status == OrderStatusEnum::SHIPMENTS) throw new Exception('订单已经发货');
  1171. if ($model->order_status != OrderStatusEnum::PAY) throw new Exception('订单已经被处理');
  1172. $model->order_status = OrderStatusEnum::SHIPMENTS;
  1173. $model->consign_time = time();
  1174. if (!$model->save()) throw new Exception($model->getErrorMessage());
  1175. return $model;
  1176. }catch(Exception $e){
  1177. self::$static_error = $e->getMessage();
  1178. return false;
  1179. }
  1180. }
  1181. /**
  1182. * @name:
  1183. * @msg: 更新订单状态
  1184. * @param {*} $order
  1185. * @return {*}
  1186. */
  1187. public static function autoUpdateStatus($order)
  1188. {
  1189. $order_details = StoreOrderDetail::getOrderDetails([['order_id' => $order->id]]);
  1190. // 正常订单详情数
  1191. $normal_count = count($order_details);
  1192. // 退款状态数
  1193. $refund_count = 0;
  1194. $not_refunding_count = 0;
  1195. $refunding_count = 0;
  1196. $feedback_completion = 0;
  1197. // 已发货状态数
  1198. $shipping_count = 0;
  1199. // 未发货状态数
  1200. $no_shipping_count = 0;
  1201. // 换货状态数
  1202. $exchange_count = 0;
  1203. // 订单完成需要关闭的订单详情数
  1204. $order_detail_close_ids = [];
  1205. foreach ($order_details as $order_detail) {
  1206. $shipping_status = $order_detail['shipping_status'];
  1207. $is_feedback = $order_detail['is_feedback'];
  1208. $shipping_status == StatusEnum::ENABLED && $shipping_count++;
  1209. $is_feedback == OrderStatusEnum::FEEDBACKED && $refund_count++;
  1210. $is_feedback == OrderStatusEnum::NOT_FEEDBACK && $not_refunding_count++;
  1211. $is_feedback == OrderStatusEnum::FEEDBACKING && $refunding_count++;
  1212. $is_feedback == OrderStatusEnum::FEEDBACKED && $feedback_completion++;
  1213. // 未发货的正常产品
  1214. if ($shipping_status == StatusEnum::DISABLED && in_array($is_feedback, OrderStatusEnum::getFeedbackMap())) {
  1215. $no_shipping_count++;
  1216. }
  1217. /****判断订单是否售后完成 --start-- ****/
  1218. if ($is_feedback == OrderStatusEnum::FEEDBACKED) {
  1219. // 订单售后完成(判断完成订单中是否存在换货数据)
  1220. $refund_exists = OrderRefund::find()
  1221. ->where(['mall_id' => $order_detail['mall_id'], 'status' => StatusEnum::ENABLED,
  1222. 'order_detail_id' => $order_detail['main_order_detail_id'], 'type' => RefundTypeEnum::EXCHANGE_GOODS,
  1223. 'store_id' => $order_detail['store_id']
  1224. ])
  1225. ->exists();
  1226. if ($refund_exists) {
  1227. $exchange_count++;
  1228. } else {
  1229. // 订单完成后订单状态为已关闭(仅为退款、退货退款)
  1230. $order_detail_close_ids[] = $order_detail['id'];
  1231. }
  1232. }
  1233. /****判断订单是否售后完成--end--****/
  1234. }
  1235. if (!empty($order_detail_close_ids)) {
  1236. // 关闭订单详情
  1237. OrderDetail::updateAll(['order_status' => OrderStatusEnum::REPEAL], ['id' => $order_detail_close_ids]);
  1238. }
  1239. // 全部已退款直接关闭
  1240. if ($normal_count === $refund_count) {
  1241. $order->close_time = time();
  1242. // 只有当退货订单中没有换货订单时,才对主订单进行关闭
  1243. if ($exchange_count == 0) {
  1244. $order->order_status = OrderStatusEnum::REPEAL;
  1245. }
  1246. if (!$order->save()) throw new Exception($order->getErrorMessage());
  1247. // return self::close(['mall_id' => $order->mall_id, 'id' => $order->id], true);
  1248. }
  1249. //未售后(当售后完成中有拒绝时也更改主订单状态)
  1250. if (!empty($not_refunding_count)) {
  1251. $order->is_feedback = OrderStatusEnum::NOT_FEEDBACK;
  1252. $order->save();
  1253. }
  1254. // 全部售后中
  1255. if ($normal_count === $refunding_count) {
  1256. $order->is_feedback = OrderStatusEnum::FEEDBACKING;
  1257. $res = $order->save();
  1258. }
  1259. // 全部售后完成
  1260. if ($normal_count === $feedback_completion) {
  1261. $order->is_feedback = OrderStatusEnum::FEEDBACKED;
  1262. $order->save();
  1263. }
  1264. // 全部已发货
  1265. if ($normal_count === $shipping_count) {
  1266. return self::delivery(['mall_id' => $order->mall_id, 'id' => $order->id]);
  1267. }
  1268. // 校验发货状态如果其他货物已发就改变订单状态
  1269. $refund_shipping_count = $refund_count + $shipping_count;
  1270. if ($normal_count == $refund_shipping_count && $order->order_status == OrderStatusEnum::PAY && $no_shipping_count == 0) {
  1271. return self::delivery(['mall_id' => $order->mall_id, 'id' => $order->id]);
  1272. }
  1273. }
  1274. /**
  1275. * @name:
  1276. * @msg: 收货
  1277. * @param {*} $params
  1278. * @return {*}
  1279. */
  1280. public static function takeDelivery($params)
  1281. {
  1282. try {
  1283. $cond = ['mall_id' => $params['mall_id'],'id' => $params['id'], 'status' => [StatusEnum::ENABLED]];
  1284. isset($params['user_id']) && $cond['user_id'] = $params['user_id'];
  1285. isset($params['store_id']) && $cond['store_id'] = $params['store_id'];
  1286. $model = self::findOne($cond);
  1287. if (empty($model)) throw new Exception('订单不存在或已删除');
  1288. if ($model->order_status == OrderStatusEnum::SING) throw new Exception('订单已经签收');
  1289. if ($model->order_status != OrderStatusEnum::SHIPMENTS) throw new Exception('订单已经被处理');
  1290. $order = Order::findOne(['order_no'=>$model['order_no']]);
  1291. if (OrderDetail::getAfterSaleCountByOrderId($order['id']) > 0) throw new Exception('请先处理或关闭订单售后');
  1292. if (StoreOrderDetail::getAfterSaleCountByOrderId($params['id']) > 0) throw new Exception('请先处理或关闭订单售后');
  1293. $model->order_status = OrderStatusEnum::SING;
  1294. $model->sign_time = time();
  1295. if (!$model->save()) throw new Exception($model->getErrorMessage());
  1296. $order->order_status = OrderStatusEnum::SING;
  1297. $order->sign_time = time();
  1298. if (!$order->save()) throw new Exception($order->getErrorMessage());
  1299. if ($model->order_source === OrderSourceEnum::SOURCE_RESERVE) {
  1300. // 同步订单状态
  1301. StoreOrderReserve::syncOrderStatus($model, $params['tech_id'] ?? null);
  1302. }
  1303. // 触发订单收货事件,事务提交完成后触发
  1304. $event = new OrderTakeDeliveryEvent($params['mall_id']);
  1305. $data['id'] = $order['id'];
  1306. $data['operator_id'] = $params['operator_id'];
  1307. $data['operator_name'] = $params['operator_name'];
  1308. Yii::$app->services->events->dispatch($event, $data, $event->listeners);
  1309. return $model;
  1310. } catch (Exception $e) {
  1311. self::$static_error = $e->getMessage();
  1312. return false;
  1313. }
  1314. }
  1315. /**
  1316. * @name:
  1317. * @msg: 订单完成
  1318. * @param {array} $params
  1319. * @return {*}
  1320. */
  1321. public static function complete(array $params)
  1322. {
  1323. try {
  1324. $cond = ['mall_id' => $params['mall_id'], 'id' => $params['id'], 'status' => [StatusEnum::ENABLED]];
  1325. isset($params['user_id']) && $cond['user_id'] = $params['user_id'];
  1326. isset($params['store_id']) && $cond['store_id'] = $params['store_id'];
  1327. $model = self::findOne($cond);
  1328. if (empty($model)) throw new Exception('订单不存在或已删除');
  1329. if ($model->order_status == OrderStatusEnum::ACCOMPLISH) throw new Exception('订单已经完成,无需重复处理');
  1330. if (!in_array($model->order_status,[OrderStatusEnum::SING,OrderStatusEnum::TAKE_FINISH])) throw new Exception('订单已经被处理');
  1331. $order = Order::findOne(['order_no'=>$model['order_no']]);
  1332. if (OrderDetail::getAfterSaleCountByOrderId($order['id']) > 0) throw new Exception('请先处理或关闭订单售后');
  1333. if (StoreOrderDetail::getAfterSaleCountByOrderId($params['id']) > 0) throw new Exception('请先处理或关闭订单售后');
  1334. $model->order_status = OrderStatusEnum::ACCOMPLISH;
  1335. $model->finish_time = time();
  1336. if (!$model->save()) throw new Exception($model->getErrorMessage());
  1337. $order->order_status = OrderStatusEnum::ACCOMPLISH;
  1338. $order->finish_time = time();
  1339. if (!$order->save()) throw new Exception($order->getErrorMessage());
  1340. if ($model->order_source === OrderSourceEnum::SOURCE_RESERVE) {
  1341. // 同步订单状态
  1342. StoreOrderReserve::syncOrderStatus($model);
  1343. }
  1344. // 触发订单过售后事件,事务提交完成后触发
  1345. $event = new OrderFinishEvent($params['mall_id']);
  1346. $order_data['id'] = $order['id'];
  1347. $order_data['order_no'] = $model['order_no'];
  1348. $order_data['operator_id'] = $params['operator_id'] ?? 0;
  1349. $order_data['operator_name'] = $params['operator_name'] ?? '系统';
  1350. Yii::$app->services->events->dispatch($event, $order_data, $event->listeners);
  1351. return $model;
  1352. } catch (Exception $e) {
  1353. self::$static_error = $e->getMessage();
  1354. return false;
  1355. }
  1356. }
  1357. /**
  1358. * 发货
  1359. * @Author bing
  1360. * @DateTime 2021-09-16 19:55:46
  1361. * @copyright: Copyright (c) 2020 广东七件事集团
  1362. * @param [type] $order_id
  1363. * @param [type] $params
  1364. * @param [type] $trigger_event
  1365. * @return bool
  1366. */
  1367. public static function OrderExpressDelivery($params,$trigger_event = true){
  1368. try{
  1369. $store_order = StoreOrder::getOne([['mall_id' => $params['mall_id'], 'id' => $params['id'],'status'=>[StatusEnum::ENABLED]]]);
  1370. $order = Order::getOne([['mall_id' => $params['mall_id'], 'order_no' => $store_order['order_no'],'status'=>[StatusEnum::ENABLED]]]);
  1371. if(empty($order)) throw new Exception('订单不存在或已删除');
  1372. $model = new OrderExpress();
  1373. $params['order_id'] = $order['id'];
  1374. $params['buyer_id'] = $order['user_id'];
  1375. $params['buyer_name'] = $order['receiver_name'];
  1376. $params['operator_username'] = $params['operator_name'];
  1377. $trans = Yii::$app->db->beginTransaction();
  1378. if(!$model->load($params,'') || !$model->save()) throw new \Exception($model->getErrorMessage());
  1379. //保存物流轨迹记录
  1380. $params['order_express_id'] = $model->id;
  1381. $res = OrderExpressLog::saveLog($params);
  1382. if ($res == false) throw new Exception(OrderExpressLog::getStaticError());
  1383. $condition['where'] = [['in', 'id', $params['order_detail_ids']],['is_feedback'=>[OrderStatusEnum::FEEDBACKING,OrderStatusEnum::FEEDBACKED]]];
  1384. $res = StoreOrderDetail::lists($condition);
  1385. if(!empty($res)) throw new \Exception('订单申请售后中,请先处理售后问题');
  1386. // 订单商品的物流状态改变
  1387. StoreOrderDetail::updateAll(['shipping_status' => StatusEnum::ENABLED], ['in', 'id', $params['order_detail_ids']]);
  1388. $store_order_detail_list = StoreOrderDetail::lists(['where'=>[['id'=>$params['order_detail_ids']]],'select'=>'main_order_detail_id']);
  1389. $main_order_detail_id = array_column($store_order_detail_list,'main_order_detail_id');
  1390. $res = OrderDetail::updateAll(['shipping_status' => StatusEnum::ENABLED], ['in', 'id',$main_order_detail_id]);
  1391. // 自动维护订单状态
  1392. $res = Order::autoUpdateStatus($order);
  1393. $res = StoreOrder::autoUpdateStatus($store_order);
  1394. if($res === false) throw new \Exception(Order::getStaticError());
  1395. $trans->commit();
  1396. if ($trigger_event) {
  1397. // 发货成功触发事件,事务提交完成后触发
  1398. $event = new \common\events\order\OrderDeliveryEvent($params['mall_id']);
  1399. $data['id'] = $model->id;
  1400. $data['operator_id'] = $params['operator_id'];
  1401. $data['operator_name'] = $params['operator_name'];
  1402. Yii::$app->services->events->dispatch($event,$data, $event->listeners);
  1403. }
  1404. return true;
  1405. }catch(Exception $e){
  1406. if(isset($trans)) $trans->rollback();
  1407. self::$static_error = $e->getMessage().$e->getFile().$e->getLine();
  1408. return false;
  1409. }
  1410. }
  1411. /**
  1412. * 修改物流
  1413. * @Author lun
  1414. * @DateTime 2021-09-24 19:55:46
  1415. * @copyright: Copyright (c) 2020 广东七件事集团
  1416. * @param [type] $params
  1417. * @return void
  1418. */
  1419. public static function OrderExpressShippingChange($params){
  1420. try{
  1421. $order_express = OrderExpress::findOne(['id' => $params['id']]);
  1422. if (empty($order_express)) throw new Exception('物流不存在或已删除');
  1423. $trans = Yii::$app->db->beginTransaction();
  1424. if(!$order_express->load($params,'') || !$order_express->save()) throw new \Exception($order_express->getErrorMessage());
  1425. OrderExpressLog::saveLog($params,true);
  1426. $trans->commit();
  1427. // 发货成功触发事件,事务提交完成后触发
  1428. $event = new \common\events\order\OrderDeliveryEvent($params['mall_id']);
  1429. $data['id'] = $params['id'];
  1430. $data['operator_id'] = $params['operator_id'];
  1431. $data['operator_name'] = $params['operator_name'];
  1432. Yii::$app->services->events->dispatch($event, $data, $event->listeners);
  1433. return true;
  1434. }catch(Exception $e){
  1435. if(isset($trans)) $trans->rollback();
  1436. self::$static_error = $e->getMessage();
  1437. return false;
  1438. }
  1439. }
  1440. //api,h5订单详情公共调用
  1441. public static function orderDetail($params){
  1442. if(empty($params['order'])){
  1443. return $params['order'];
  1444. }
  1445. if(empty($params['order']['order_no'])) return $params['order'];
  1446. $data = $params['order'];
  1447. $order_no = $params['order']['order_no'];
  1448. $store_order = StoreOrder::findOne(['order_no'=>$order_no]);
  1449. if(empty($store_order)) return $data;
  1450. $store = Store::findOne(['id'=>$store_order['store_id']]);
  1451. $region_ids = [$store['province_id'],$store['city_id'],$store['district_id']];
  1452. $region_list = Region::lists(['where'=>[['id'=>$region_ids]],'select'=>'id,name','index'=>'id']);
  1453. $province = $region_list[$store['province_id']]['name'];
  1454. $city = $region_list[$store['city_id']]['name'];
  1455. $district = $region_list[$store['district_id']]['name'];
  1456. $order = Order::findOne(['order_no'=>$order_no]);
  1457. $data['user_mobile'] = $store_order['mobile'];
  1458. $data['latitude'] = $store['latitude'];
  1459. $data['longitude'] = $store['longitude'];
  1460. $data['shop_mobile'] = $store['shop_mobile'];
  1461. $data['store_name'] = $store['store_name'];
  1462. $data['logo_img'] = $store['logo_img'];
  1463. $data['clerk_code'] = !empty($order['clerk_code'])?$order['clerk_code']:$order['id'];
  1464. $data['store_address'] = $province.$city.$district.$store['address'];
  1465. $marketing = self::getMarketingInfo($store_order);
  1466. $data['marketing'] = $marketing;
  1467. $data['pickup'] = StoreOrderPickup::getPickupDataByOrderId($store_order->id) ?? [];
  1468. $store_goods_attr_ids = $store_goods_ids = [];
  1469. foreach ($order['detail'] as $v){
  1470. if(!empty($v['store_id'])){
  1471. $store_goods_attr_ids[]=$v['goods_attr_id'];
  1472. $store_goods_ids[]=$v['goods_id'];
  1473. }
  1474. }
  1475. $store_goods_attr_list = [];
  1476. if(!empty($store_goods_attr_ids)){
  1477. $store_goods_attr_list = StoreGoodsAttr::lists(['where'=>[['id'=>$store_goods_attr_ids]],'select'=>'id,original_price','index'=>'id']);
  1478. }
  1479. if(!empty($store_goods_ids)){
  1480. $store_goods_list = StoreGoods::lists(['where'=>[['id'=>$store_goods_ids]],'select'=>'id,unit,goods_source,goods_type','index'=>'id']);
  1481. }
  1482. foreach ($data['detail'] as $k => $v){
  1483. if(!empty($v['store_id'])){
  1484. $data['detail'][$k]['is_show_return_btn'] = 1;
  1485. $data['detail'][$k]['original_price'] = $store_goods_attr_list[$v['goods_attr_id']]['original_price']??0;
  1486. $data['detail'][$k]['unit'] = $data['detail'][$k]['order_source'] = $data['detail'][$k]['goods_type'] = '';
  1487. if(isset($store_goods_list[$v['goods_id']])){
  1488. $goods = $store_goods_list[$v['goods_id']];
  1489. $data['detail'][$k]['unit'] = $goods['unit'];
  1490. $data['detail'][$k]['order_source'] = $goods['goods_source'];
  1491. $data['detail'][$k]['goods_type'] = $goods['goods_type'];
  1492. }
  1493. }
  1494. }
  1495. return $data;
  1496. }
  1497. public static function getMarketingInfo($order)
  1498. {
  1499. $member_price = $coupon_discount_money = $full_reduce_money = $score = $score_deduct_money = $agent_deduct = 0;
  1500. if (!empty($order['detail'])) {
  1501. $currency = [];
  1502. $order_detail_ids = array_column($order['detail'], 'id');
  1503. $order_marketing_list = StoreOrderMarketing::lists(['where' => [['order_detail_id' => $order_detail_ids]]]);
  1504. foreach ($order_marketing_list as $value) {
  1505. $member_price += $value['member_price_deduct'];
  1506. $coupon_discount_money += $value['coupon_discount_money'];
  1507. $full_reduce_money += $value['full_reduce_money'];
  1508. $deduct_currency = json_decode($value['deduct_currency'],'true');
  1509. if(!empty($deduct_currency['score'])){
  1510. $score_deduct_money += $deduct_currency['score']['money'];
  1511. }
  1512. $agent_deduct += $value['agent_deduct'];
  1513. }
  1514. }
  1515. $member_price = bcmul($member_price,1,2);
  1516. $coupon_discount_money = bcmul($coupon_discount_money,1,2);
  1517. $agent_deduct = bcmul($agent_deduct,1,2);
  1518. $marketing['deduct'] = [
  1519. 'member_price' => ['name' => '会员优惠', 'money' => -$member_price],
  1520. 'coupon' => ['name' => '优惠券', 'money' => -$coupon_discount_money],
  1521. 'score' => ['name' => '积分抵扣', 'money' => -$score_deduct_money],
  1522. ];
  1523. !empty($currency) && $marketing['deduct'] = array_merge($marketing['deduct'], $currency);
  1524. if (MallAddons::isInstall($order['mall_id'], AddonsEnum::ADDONS_NAME_AGENT)){
  1525. $marketing['deduct']['agent_deduct'] = ['name' => '经销商内购商品抵扣', 'money' => -$agent_deduct];
  1526. }
  1527. return $marketing;
  1528. }
  1529. public static function updateCode()
  1530. {
  1531. $i = 1;
  1532. $page_size = 1000;
  1533. while ($list = StoreOrder::find()
  1534. ->andWhere(['=', 'shipping_type', 2])
  1535. ->offset(($i - 1) * $page_size)->limit($page_size)->all()) {
  1536. foreach ($list as $item) {
  1537. $id = $item['id'];
  1538. $order_no = $item['order_no'];
  1539. $code = StoreOrder::getClerkCode($item['mall_id']);
  1540. $sql = "update qimall_addons_store_order set clerk_code = {$code} where id = {$id}";
  1541. $res = \Yii::$app->db->createCommand($sql)->execute();
  1542. var_dump($res);
  1543. $sql = "update qimall_order set clerk_code = {$code} where order_no = '{$order_no}'";
  1544. \Yii::$app->db->createCommand($sql)->execute();
  1545. var_dump($res);
  1546. }
  1547. $i++;
  1548. }
  1549. }
  1550. /**
  1551. * 获取门店自提订单核销信息
  1552. * @Author:hua
  1553. * @Date:2024-03-07 14:27
  1554. * @Copyright:copyright(c)2024 广东七件事集团
  1555. * @param $params
  1556. * @return array|mixed|void
  1557. */
  1558. public static function getStoreSelfPickupOrderClerkData($params){
  1559. try {
  1560. $select = 'id,mall_id,store_id,order_no,receiver_name,mobile,pay_money,shipping_money,original_goods_price,coupon_money,goods_price,order_status,pay_status,
  1561. shipping_status,review_status,is_feedback,address,created_at,pay_time,region_name,remark,consign_time,finish_time,sign_time,shipping_type,payment_type,score,score_money,marketing_id,marketing_type,extra_info,order_source';
  1562. $where = [];
  1563. $clerk_code = $params['clerk_code'];
  1564. $mall_id = $params['mall_id'];
  1565. $platform = $params['platform'];
  1566. $user_id = $params['user_id'];
  1567. $where[] = ['clerk_code' => $clerk_code];
  1568. $where[] = ['mall_id' => $mall_id];
  1569. $where[] = ['status' => StatusEnum::ENABLED];
  1570. $order = Order::getOne($where, true, ['detail' => function ($query) {
  1571. $query->select('id,order_id,goods_id,goods_name,pic_url,num,price,is_feedback,sign_id,goods_attr_name,order_status,adjust_money,extra_info');
  1572. }], false, $select);
  1573. if (empty($order))throw new Exception('该订单不存在');
  1574. $store_id = $order['store_id'];
  1575. $store = Store::getOne([['id' => $store_id]], true, [], false, 'id,user_id,balance');
  1576. $store_user_id = $store['user_id'];
  1577. $where = [
  1578. ['mall_id' => $mall_id],
  1579. ['store_id' => $store_id],
  1580. ['status' => StatusEnum::ENABLED]
  1581. ];
  1582. if($user_id != $store_user_id){
  1583. $where[] = ['user_id'=>$user_id];
  1584. }
  1585. $rse = StoreClerk::getOne($where);
  1586. if (empty($rse)) throw new Exception('你不是核销员');
  1587. $marketing = OrderMarketing::getMarketingInfo($order);
  1588. $order['order_status_text'] = OrderStatusEnum::getMap();
  1589. $order['is_feedback_text'] = OrderStatusEnum::getFeedbackMap();
  1590. $order['shipping_type_text'] = ShippingTypeEnum::getMap();
  1591. $order['payment_type_text'] = PayTypeEnum::getMap();
  1592. $order['pay_type_list'] = \Yii::$app->services->pay->getEnablePayment($mall_id, $platform);
  1593. $adjust_money = array_sum(array_column($order['detail'], 'adjust_money'));//预留字段
  1594. if ($adjust_money) {
  1595. $order['change_price'] = $adjust_money;
  1596. }
  1597. $order['marketing'] = $marketing;
  1598. $order['marketing_type_map'] = MarketingTypeEnum::getMap();
  1599. $order_setting = Yii::$app->services->setting->mall->get($mall_id, 'order');
  1600. $order['payment_expire_time'] = $order_setting['payment_expire_time'] ?? 30;
  1601. $order['auto_receiving_time'] = $order_setting['auto_receiving_time'] ?? 14;
  1602. // 获取订单详情的状态文字描述
  1603. $order['status_text'] = OrderStatusEnum::getApiStatus($order['status'], $order['shipping_type']);
  1604. $order['status'] == OrderStatusEnum::NOT_PAY && $order['status_text']['desc'] = $order['payment_expire_time'] . $order['status_text']['desc'];
  1605. $order['status'] == OrderStatusEnum::SHIPMENTS && $order['status_text']['desc'] = $order['auto_receiving_time'] . $order['status_text']['desc'];
  1606. // 公共调用
  1607. $order = GlobalInvoke::exec(GlobalInvoke::ORDER_DETAIL, $mall_id, [
  1608. 'order' => $order,
  1609. 'mall_id' => $mall_id,
  1610. ]) ?: $order;
  1611. $order['clerk_code_pre'] = ClerkEnum::O2O_SELF_PICKUP_ORDERS_CLERK_CODE_PRE;
  1612. return $order;
  1613. }catch (Exception $e){
  1614. throw new Exception($e->getMessage());
  1615. }
  1616. }
  1617. public static function getClerkLogDetail($params){
  1618. try {
  1619. $clerk_log_model = \common\models\common\ClerkLog::findOne(['id'=>$params['clerk_log_id'],'mall_id'=>$params['mall_id'],'user_id'=>$params['user_id'],'type'=>$params['type']]);
  1620. $extra = json_decode($clerk_log_model['extra'],true);
  1621. $order_id = $extra['order_id'];
  1622. $select = 'id,mall_id,store_id,order_no,receiver_name,mobile,pay_money,shipping_money,original_goods_price,coupon_money,goods_price,order_status,pay_status,
  1623. shipping_status,review_status,is_feedback,address,created_at,pay_time,region_name,remark,consign_time,finish_time,sign_time,shipping_type,payment_type,score,score_money,marketing_id,marketing_type,extra_info,order_source';
  1624. $where = [];
  1625. $mall_id = $params['mall_id'];
  1626. $platform = $params['platform'];
  1627. $user_id = $params['user_id'];
  1628. $where[] = ['id' => $order_id];
  1629. $where[] = ['mall_id' => $mall_id];
  1630. $where[] = ['status' => StatusEnum::ENABLED];
  1631. $order = Order::getOne($where, true, ['detail' => function ($query) {
  1632. $query->select('id,order_id,goods_id,goods_name,pic_url,num,price,is_feedback,sign_id,goods_attr_name,order_status,adjust_money,extra_info');
  1633. }], false, $select);
  1634. if (empty($order)) {
  1635. throw new Exception('该订单不存在');
  1636. }
  1637. $store_id = $order['store_id'];
  1638. $store = Store::getOne([['id' => $store_id]], true, [], false, 'id,user_id,balance');
  1639. $store_user_id = $store['user_id'];
  1640. $where = [
  1641. ['mall_id' => $mall_id],
  1642. ['store_id' => $store_id],
  1643. ['status' => StatusEnum::ENABLED]
  1644. ];
  1645. if($user_id != $store_user_id){
  1646. $where[] = ['user_id'=>$user_id];
  1647. }
  1648. $marketing = OrderMarketing::getMarketingInfo($order);
  1649. $order['order_status_text'] = OrderStatusEnum::getMap();
  1650. $order['is_feedback_text'] = OrderStatusEnum::getFeedbackMap();
  1651. $order['shipping_type_text'] = ShippingTypeEnum::getMap();
  1652. $order['payment_type_text'] = PayTypeEnum::getMap();
  1653. $order['pay_type_list'] = \Yii::$app->services->pay->getEnablePayment($mall_id, $platform);
  1654. $adjust_money = array_sum(array_column($order['detail'], 'adjust_money'));//预留字段
  1655. if ($adjust_money) {
  1656. $order['change_price'] = $adjust_money;
  1657. }
  1658. $order['marketing'] = $marketing;
  1659. $order['marketing_type_map'] = MarketingTypeEnum::getMap();
  1660. $order_setting = Yii::$app->services->setting->mall->get($mall_id, 'order');
  1661. $order['payment_expire_time'] = $order_setting['payment_expire_time'] ?? 30;
  1662. $order['auto_receiving_time'] = $order_setting['auto_receiving_time'] ?? 14;
  1663. // 获取订单详情的状态文字描述
  1664. $order['status_text'] = OrderStatusEnum::getApiStatus($order['status'], $order['shipping_type']);
  1665. $order['status'] == OrderStatusEnum::NOT_PAY && $order['status_text']['desc'] = $order['payment_expire_time'] . $order['status_text']['desc'];
  1666. $order['status'] == OrderStatusEnum::SHIPMENTS && $order['status_text']['desc'] = $order['auto_receiving_time'] . $order['status_text']['desc'];
  1667. // 公共调用
  1668. $order = GlobalInvoke::exec(GlobalInvoke::ORDER_DETAIL, $mall_id, [
  1669. 'order' => $order,
  1670. 'mall_id' => $mall_id,
  1671. ]) ?: $order;
  1672. $order['clerk_code_pre'] = ClerkEnum::O2O_SELF_PICKUP_ORDERS_CLERK_CODE_PRE;
  1673. return $order;
  1674. }catch (Exception $e){
  1675. throw new Exception($e->getMessage());
  1676. }
  1677. }
  1678. /**
  1679. * 核销门店自提订单
  1680. * @Author:hua
  1681. * @Date:2024-03-07 14:28
  1682. * @Copyright:copyright(c)2024 广东七件事集团
  1683. * @param $params
  1684. * @return StoreClerkLog
  1685. */
  1686. public static function storeSelfPickupOrderClerk($params){
  1687. $t = Yii::$app->db->beginTransaction();
  1688. try {
  1689. $clerk_code = $params['clerk_code'];
  1690. $mall_id = $params['mall_id'];
  1691. $user_id = $params['user_id'];
  1692. $order = Order::findOne(['mall_id'=>$mall_id,'clerk_code'=> $clerk_code,'status'=>StatusEnum::ENABLED]);
  1693. if (empty($order)) throw new \Exception('自提订单不存在');
  1694. $store = Store::getOne([['id' => $order->store_id]], true, [], false, 'id,user_id,balance,logo_img,store_name');
  1695. $store_user_id = $store['user_id'];
  1696. $store_id = $order['store_id'];
  1697. $where = [
  1698. ['mall_id' => $mall_id],
  1699. ['store_id' => $store_id],
  1700. ['status' => StatusEnum::ENABLED]
  1701. ];
  1702. if($user_id != $store_user_id){
  1703. $where[] = ['user_id'=>$user_id];
  1704. }
  1705. $store_clerk = StoreClerk::getOne($where);
  1706. if (empty($store_clerk)) throw new Exception('你不是核销员');
  1707. $params['clerk_id'] = $store_clerk['id'];
  1708. $order->order_status = OrderStatusEnum::TAKE_FINISH;
  1709. $order->sign_time = time();
  1710. $res = $order->save();
  1711. if($res==false) throw new \Exception($order->getErrorMessage());
  1712. $store_order = StoreOrder::getOne([['order_no' => $order['order_no']], ['mall_id' => $params['mall_id']], ['store_id' => $order['store_id']]]);
  1713. if (empty($store_order)) throw new \Exception('门店自提订单不存在');
  1714. if ($store_order->order_status != OrderStatusEnum::TAKE) throw new \Exception('该订单不是待自提');
  1715. if ($store_order->order_status == OrderStatusEnum::TAKE_FINISH) throw new \Exception('已自提');
  1716. if ($store_order->shipping_type != ShippingTypeEnum::PICKUP) throw new \Exception('该订单不是自提订单');
  1717. $insert_data = $params;
  1718. $insert_data['store_id'] = $store_clerk['store_id'];
  1719. $insert_data['clerk_id'] = $store_clerk['id'];
  1720. $insert_data['order_no'] = $store_order['order_no'];
  1721. $insert_data['user_id'] = $store_order['user_id'];
  1722. $insert_data['mobile'] = $store_order['mobile'];
  1723. $model = new StoreClerkLog();
  1724. $model->loadDefaultValues();
  1725. if (!$model->load($insert_data, '')) throw new \Exception($model->getErrorMessage());
  1726. if (!$model->save()) throw new \Exception($model->getErrorMessage());
  1727. $store_order->order_status = OrderStatusEnum::TAKE_FINISH;
  1728. $store_order->sign_time = time();
  1729. $store_order->save();
  1730. $order_detail = OrderDetail::findOne(['order_id'=>$order['id']]);
  1731. if(MallAddons::isInstall($mall_id,'Clerk')){
  1732. $add_data = [
  1733. 'mall_id'=>$mall_id,
  1734. 'name'=>$order_detail['goods_name'],
  1735. 'clerk_code'=>$clerk_code,
  1736. 'type'=>ClerkEnum::O2O_SELF_PICKUP_ORDERS_CLERK_CODE_PRE,
  1737. 'extra'=>json_encode(['order_no'=>$order['order_no']])
  1738. ];
  1739. ClerkLog::setData($add_data);
  1740. }
  1741. $store_goods = StoreGoods::findOne(['id'=>$order_detail['goods_id']]);
  1742. $nums = OrderDetail::find()->where(['order_id'=>$order['id']])->sum('num');
  1743. $add_clerk_log_data = [
  1744. 'mall_id' => $params['mall_id'],
  1745. 'user_id' => $user_id,
  1746. 'mall_logo' => $store['logo_img'],
  1747. 'mall_name' => $store['store_name'],
  1748. 'name' => $order_detail['goods_name'],
  1749. 'pic' => $order_detail['pic_url'],
  1750. 'clerk_code' => (string)$params['clerk_code'],
  1751. 'type' => ClerkEnum::O2O_SELF_PICKUP_ORDERS_CLERK_CODE_PRE,
  1752. 'extra' => json_encode([
  1753. 'pay_money' => $store_order['pay_money'],
  1754. 'order_money' => $store_order['pay_money'],
  1755. 'clerk_nums' => $nums??0,
  1756. 'subtitle' => $store_goods['subtitle']??'',
  1757. 'order_id' => $order['id'] ?? 0,
  1758. ]),
  1759. ];
  1760. $clerk_log_model = \common\models\common\ClerkLog::setData($add_clerk_log_data);
  1761. if ($clerk_log_model == false) {
  1762. throw new \Exception(\common\models\common\ClerkLog::getStaticError());
  1763. }
  1764. // 维护累计核销金额及累计核销订单数
  1765. StoreClerk::incrNumsAndTotalMoney($store_clerk['id'], $nums, $store_order['pay_money']);
  1766. $t->commit();
  1767. // 微信小程序发货
  1768. $event = new StoreSelfPickupOrderClerkEvent($mall_id);
  1769. $data['id'] = $order['id'];
  1770. Yii::$app->services->events->dispatch($event, $data, $event->listeners);
  1771. return $model;
  1772. } catch (\Exception $e) {
  1773. $t->rollBack();
  1774. throw new Exception($e->getMessage());
  1775. }
  1776. }
  1777. /**
  1778. * 通过订单ID获取订单
  1779. *
  1780. * @param integer $mall_id
  1781. * @param integer $id
  1782. * @param string $fields
  1783. * @return static|null
  1784. */
  1785. public static function getOrderByOrderId(int $mall_id, int $id, string $fields = 'id, shipping_type, store_id')
  1786. {
  1787. return static::find()
  1788. ->select($fields)
  1789. ->where(['mall_id' => $mall_id, 'id' => $id])
  1790. ->one();
  1791. }
  1792. /**
  1793. * 是否自提订单
  1794. *
  1795. * @return boolean
  1796. */
  1797. public function isPuckup()
  1798. {
  1799. return $this->shipping_type == ShippingTypeEnum::PICKUP;
  1800. }
  1801. public static function exportHandle(array $data)
  1802. {
  1803. date_default_timezone_set('Asia/Shanghai');
  1804. $download_id = $data['download_id'] ?? 0;
  1805. $download = Download::findOne(['id' => $download_id]);
  1806. if ($download) {
  1807. try {
  1808. $params = json_decode($download->params, true);
  1809. $filename = $download->name;
  1810. $type = $download->type;
  1811. $order_detail_model = StoreOrderDetail::find()->alias('od');
  1812. $order_detail_model->where(['od.mall_id' => $params['mall_id']]);
  1813. if (isset($params['is_reserve']) && $params['is_reserve'] == 1) {
  1814. $order = StoreOrder::find()->where(['order_source' => OrderSourceEnum::SOURCE_RESERVE, 'mall_id' => $params['mall_id'], 'store_id' => $params['store_id']])->asArray()->all();
  1815. $order_detail_model->andWhere(['in', 'od.order_id', array_column($order, 'id')]);
  1816. $order_detail_model->andWhere(['in', 'od.store_id', [0, $params['store_id']]]);
  1817. } else {
  1818. if (isset($params['store_id']) && !empty($params['store_id'])) {
  1819. $order_detail_model->andWhere(['od.store_id' => $params['store_id']]);
  1820. } else {
  1821. $order_detail_model->andWhere(['>', 'od.store_id', 0]);
  1822. }
  1823. }
  1824. $is_show_mch_name = 0;
  1825. $order_detail_model->andWhere(['>=', 'od.status', StatusEnum::DISABLED]);
  1826. if (!empty($params['ids'])) {
  1827. $order_detail_model->andWhere(['od.order_id' => $params['ids']]);
  1828. }
  1829. if (!empty($params['order_no'])) {
  1830. $order = self::findOne(['order_no' => $params['order_no']]);
  1831. $order_detail_model->andWhere(['=', 'od.order_id', $order->id]);
  1832. }
  1833. if (!empty($params['mobile'])) {
  1834. $user = User::find()->where(['like', 'mobile', $params['mobile'] . '%', false])->all();
  1835. $where[] = ['in', 'user_id', array_column($user, 'id')];
  1836. $order_detail_model->andWhere(['in', 'od.user_id', array_column($user, 'id')]);
  1837. }
  1838. if (!empty($params['start'])) {
  1839. $order_detail_model->andWhere(['>=', 'od.created_at', strtotime($params['start'])]);
  1840. }
  1841. if (!empty($params['end'])) {
  1842. $order_detail_model->andWhere(['<=', 'od.created_at', strtotime($params['end'])]);
  1843. }
  1844. if (isset($params['order_status']) && $params['order_status'] !== '' && $params['order_status'] != 999) {
  1845. $order_detail_model->andWhere(['=', 'od.order_status', $params['order_status']]);
  1846. }
  1847. if (!empty($params['type']) && !empty($params['type_value'])) {
  1848. switch ($params['type']) {
  1849. case 'mobile':
  1850. $uids = User::find()->select('id')
  1851. ->where(['mall_id' => $params['mall_id']])
  1852. ->andWhere(['like', 'mobile', $params['type_value'] . '%', false])->column();
  1853. !empty($uids) && $order_detail_model->andWhere(['od.user_id' => $uids]);
  1854. break;
  1855. case 'username':
  1856. $uids = User::find()->select('id')
  1857. ->where(['mall_id' => $params['mall_id']])
  1858. ->andWhere(['username' => $params['type_value']])->column();
  1859. !empty($uids) && $order_detail_model->andWhere(['od.user_id' => $uids]);
  1860. break;
  1861. case 'user_id':
  1862. $order_detail_model->andWhere(['od.user_id' => $params['type_value']]);
  1863. break;
  1864. case 'order_id':
  1865. $order_detail_model->andWhere(['od.order_id' => $params['type_value']]);
  1866. break;
  1867. case 'goods_name':
  1868. $order_detail_model->andWhere(['like', 'od.goods_name', $params['type_value'] . '%', false]);
  1869. break;
  1870. case 'consignee':
  1871. case 'consignee_mobile':
  1872. if ($params['type'] == 'consignee') {
  1873. $storeWhere = ['like', 'receiver_name', $params['type_value'] . '%', false];
  1874. } else {
  1875. $storeWhere = ['like', 'mobile', $params['type_value'] . '%', false];
  1876. }
  1877. $orderIds = StoreOrder::find()
  1878. ->where(['status' => StatusEnum::ENABLED, 'mall_id' => $params['mall_id']])
  1879. ->andWhere($storeWhere)->select('id')
  1880. ->column();
  1881. if (!empty($orderIds)) {
  1882. $order_detail_model->andWhere(['in', 'od.order_id', array_unique($orderIds)]);
  1883. }
  1884. break;
  1885. default:
  1886. }
  1887. }
  1888. if (!empty($params['type'] == 'user_id') && !empty($params['type_value'])) {
  1889. $order_detail_model->andWhere(['=', 'od.user_id', $params['type_value']]);
  1890. }
  1891. $is_left_join = false;
  1892. if (!empty($params['payment_type'])) {
  1893. $order_detail_model->leftJoin(self::tableName().'as o','o.id=od.order_id')->andWhere(
  1894. ['=','o.payment_type',$params['payment_type']]
  1895. );
  1896. $is_left_join = true;
  1897. }
  1898. if (!empty($params['shipping_type'])) {
  1899. $order_detail_model->andWhere(['=', 'o.shipping_type', $params['shipping_type']]);
  1900. }
  1901. if(!empty($params['marketing_type'])){
  1902. if($params['marketing_type'] != 'order_user_handle_finish'){
  1903. $order_detail_model->andWhere(['=', 'o.marketing_type', $params['marketing_type']]);
  1904. }else{
  1905. $order_user_handle = OrderUserHandle::lists(['where' => [['mall_id' => $params['mall_id']], ['status' => StatusEnum::ENABLED]], 'select' => 'order_id']);
  1906. $order_detail_model->andWhere(['in', 'o.id', array_column($order_user_handle, 'order_id')]);
  1907. }
  1908. }
  1909. if (!empty($params['province'])) {
  1910. if(!$is_left_join){
  1911. $order_detail_model->leftJoin(self::tableName().'as o','o.id=od.order_id');
  1912. }
  1913. $order_detail_model->andWhere(['IN', 'o.id', (array)self::find()->where(['mall_id' => $params['mall_id']])
  1914. ->andWhere(['OR',['province' => $params['province']], ['city' => $params['province']], ['area' => $params['province']]])
  1915. ->select('id')
  1916. ->asArray()
  1917. ->column()]);
  1918. }
  1919. $order_detail_model->with(['order', 'user' => function ($query) {
  1920. $query->select('id,nickname,username,mobile');
  1921. }]);
  1922. $fields = $params['fields'];
  1923. $fields_arr = self::fieldsList();
  1924. $fields_arr['create_type'] = '创建方式';
  1925. $have_select_field_arr = [];
  1926. $is_attr = 0;
  1927. foreach ($fields as $value) {
  1928. if ($value == 'goods_attr_name') {
  1929. $is_attr = 1;
  1930. }
  1931. if (isset($fields_arr[$value])) $have_select_field_arr[] = $fields_arr[$value];
  1932. if ($value == 'mch_id') {
  1933. $have_select_field_arr[] = '商户名称';
  1934. }
  1935. }
  1936. $csv = new CsvTool();
  1937. $csv->filename = $filename;
  1938. $csv->file_dirname = DownloadEnum::getTypeStorageDirMap($type);
  1939. $csv->export_mode = CsvTool::EXPORT_MODE_ASYNC;
  1940. $csv->header = $have_select_field_arr;
  1941. $order_status_list = OrderStatusEnum::getMap();
  1942. $shipping_status_list = ShippingStatusEnum::getMap();
  1943. if ($params['is_reserve'] == 1) {
  1944. $order_status_list = OrderStatusEnum::getReserveMap();
  1945. $shipping_status_list = [
  1946. 0 => '待预约',
  1947. 1 => '上门服务',
  1948. 2 => '到店服务',
  1949. ];
  1950. }
  1951. $payment_type_list = PayTypeEnum::getMap();
  1952. $order_ids_arr = [];
  1953. foreach ($order_detail_model->batch() as $order_details) {
  1954. $goods_attr_arr = [];
  1955. if ($is_attr) {
  1956. $goods_attr_ids = array_column($order_details, 'goods_attr_id');
  1957. $goods_attr_arr = GoodsAttr::lists(['where' => [['id' => $goods_attr_ids]], 'select' => 'id,goods_no', 'index' => 'id']);
  1958. }
  1959. $mch_list = [];
  1960. if (!empty($is_show_mch_name)) {
  1961. $mch_ids = array_unique(array_column($order_details, 'mch_id'));
  1962. $mch_list = Mch::lists(['where' => [['id' => $mch_ids]], 'select' => 'id,store_name', 'index' => 'id']);
  1963. }
  1964. $csv->data = array_map(function ($order_detail) use ($fields, $payment_type_list, $order_status_list, $shipping_status_list, $goods_attr_arr, $mch_list,&$order_ids_arr) {
  1965. $row = [];
  1966. foreach ($fields as $field) {
  1967. // 收货人地址切割
  1968. if (!empty($order_detail['order']['region_name'])) {
  1969. $region_name = explode(' ', $order_detail['order']['region_name']);
  1970. }
  1971. // 判断是否安装社区团购
  1972. $is_install = MallAddons::isInstall($order_detail['mall_id'], AddonsEnum::ADDONS_NAME_COMMUNITY);
  1973. if ($is_install && $order_detail['order']['shipping_type'] == 2 && !empty($order_detail['order']['extra_info'])) {
  1974. $extra_info = json_decode($order_detail['order']['extra_info'], true);
  1975. if (!empty($extra_info['head_id'])) {
  1976. $headInfo = (new HeadService())->getHeadInfo($order_detail['mall_id'], $extra_info['head_id']);
  1977. if (!empty($headInfo)) {
  1978. $region_name = [
  1979. $headInfo['province'] ?? '',
  1980. $headInfo['city'] ?? '',
  1981. $headInfo['district'] ?? ''
  1982. ];
  1983. $order_detail['order']['address'] = $headInfo['address'];
  1984. }
  1985. }
  1986. }
  1987. switch (true) {
  1988. case (in_array($field, ['created_at'])):
  1989. $row[] = !empty($order_detail[$field]) ? date('Y-m-d H:i:s', $order_detail[$field]) : '';
  1990. break;
  1991. case (in_array($field, ['pay_time', 'consign_time', 'sign_time'])):
  1992. $row[] = !empty($order_detail['order'][$field]) ? date('Y-m-d H:i:s', $order_detail['order'][$field]) : '';
  1993. break;
  1994. case (in_array($field, ['order_no', 'mobile', 'receiver_name', 'region_name', 'address', 'shipping_money', 'seller_remark', 'remark'])):
  1995. $row[] = !empty($order_detail['order'][$field]) ? $order_detail['order'][$field] : '';
  1996. break;
  1997. case ($field == 'pay_money'):
  1998. if (!isset($order_ids_arr[$field]) || !in_array($order_detail['order_id'],$order_ids_arr[$field])) {
  1999. $row[] = !empty($order_detail['order'][$field]) ? $order_detail['order'][$field] : '';
  2000. $order_ids_arr[$field][]=$order_detail['order_id'];
  2001. } else {
  2002. $row[] = '';
  2003. }
  2004. break;
  2005. case (in_array($field, ['order_id'])):
  2006. $row[] = !empty($order_detail['order']['id']) ? $order_detail['order']['id'] : '';
  2007. break;
  2008. case ($field == 'payment_type'):
  2009. if (isset($order_detail['order'][$field]) && $order_detail['order'][$field] >= 0) {
  2010. $row[] = !empty($payment_type_list[$order_detail['order'][$field]]) ? $payment_type_list[$order_detail['order'][$field]] : '';
  2011. } else {
  2012. $row[] = '';
  2013. }
  2014. break;
  2015. case ($field == 'order_status'):
  2016. $row[] = !empty($order_status_list[$order_detail[$field]]) ? $order_status_list[$order_detail[$field]] : '';
  2017. break;
  2018. case ($field == 'order_type'):
  2019. if ($order_detail['order']['is_feedback'] != StatusEnum::DISABLED) {
  2020. if ($order_detail['order']['is_feedback'] == StatusEnum::ENABLED) {
  2021. $row[] = '售后订单维权中';
  2022. } else {
  2023. $row[] = '售后订单维权完成';
  2024. }
  2025. } else {
  2026. $row[] = '';
  2027. }
  2028. //var_dump($order_detail['order']['is_feedback'],$row);
  2029. break;
  2030. case ($field == 'shipping_status'):
  2031. $row[] = !empty($shipping_status_list[$order_detail[$field]]) ? $shipping_status_list[$order_detail[$field]] : '';
  2032. break;
  2033. case ($field == 'pay_status'):
  2034. $row[] = !empty($order_detail['order'][$field]) ? '已付款' : '未付款';
  2035. break;
  2036. case ($field == 'out_trade_no'):
  2037. $row[] = PaymentTradeOrder::getOutTradeNoOfOrderNo($order_detail['order']['order_no'] ?? '') ?: '';
  2038. break;
  2039. case ($field == 'user_mobile'):
  2040. $row[] = $order_detail['user']['mobile'] ?? '';
  2041. break;
  2042. case ($field == 'username'):
  2043. $row[] = $order_detail['user']['username'] ?? '';
  2044. break;
  2045. case ($field == 'nickname'):
  2046. $row[] = $order_detail['user']['nickname'] ?? '';
  2047. break;
  2048. case ($field == 'detail_address'):
  2049. $str = '';
  2050. if (!empty($region_name[0])) $str .= $region_name[0];
  2051. if (!empty($region_name[1])) $str .= $region_name[1];
  2052. if (!empty($region_name[2])) $str .= $region_name[2];
  2053. if (!empty($region_name[3])) $str .= $region_name[3];
  2054. $str .= $order_detail['order']['address'];
  2055. $row[] = $str;
  2056. break;
  2057. case ($field == 'province'):
  2058. $row[] = $region_name[0] ?? '';
  2059. break;
  2060. case ($field == 'city'):
  2061. $row[] = $region_name[1] ?? '';
  2062. break;
  2063. case ($field == 'area'):
  2064. $row[] = $region_name[2] ?? '';
  2065. break;
  2066. case ($field == 'town'):
  2067. $row[] = $region_name[3] ?? '';
  2068. break;
  2069. case ($field == 'goods_attr_name'):
  2070. $str = !empty($order_detail[$field]) ? $order_detail[$field] : '';
  2071. if (!empty($goods_attr_arr[$order_detail['goods_attr_id']]['goods_no'])) {
  2072. if (!empty($str)) {
  2073. $str .= ';';
  2074. }
  2075. $str .= '货号:' . $goods_attr_arr[$order_detail['goods_attr_id']]['goods_no'];
  2076. }
  2077. $row[] = $str;
  2078. break;
  2079. case ($field == 'mch_id'):
  2080. if (isset($mch_list) && isset($mch_list[$order_detail[$field]])) {
  2081. $row[] = $mch_list[$order_detail[$field]]['store_name'];
  2082. }
  2083. break;
  2084. case ($field == 'user_id'):
  2085. $row[] = !empty($order_detail[$field]) ? $order_detail[$field] : '';
  2086. break;
  2087. case ($field == 'cost_total_price'):
  2088. if (isset($order_detail['cost_price']) && isset($order_detail['num']))
  2089. {
  2090. $row[] = bcmul($order_detail['num'], $order_detail['cost_price'], 2);
  2091. }else {
  2092. $row[] = '';
  2093. }
  2094. break;
  2095. default:
  2096. $row[] = !empty($order_detail[$field]) ? $order_detail[$field] : '';
  2097. }
  2098. }
  2099. return $row;
  2100. }, $order_details);
  2101. $csv->export();
  2102. }
  2103. $csv->updateDown($download, $params['mall_id']);
  2104. return true;
  2105. } catch (\Exception $e) {
  2106. $download->status = 3;
  2107. $res = $download->save();
  2108. var_dump($e->getMessage() . $e->getFile() . $e->getLine());
  2109. self::setStaticError($e->getMessage());
  2110. return $e->getMessage();
  2111. }
  2112. }
  2113. }
  2114. public static function getOneData($params, $orderBy = 'id desc')
  2115. {
  2116. return static::find()->where($params)->orderBy($orderBy)->asArray()->one();
  2117. }
  2118. /**
  2119. * 修复门店预约商品的核销码
  2120. * @return void
  2121. */
  2122. public static function fixReserveClerkCode(){
  2123. $offset = 1;
  2124. $limit = 1000;
  2125. while ($list = StoreOrder::lists([
  2126. 'where'=>[
  2127. ['order_source'=>'Reserve']
  2128. ],
  2129. 'limit'=>$limit,
  2130. 'offset'=>($offset - 1) * $limit],false)) {
  2131. foreach ($list as $item){
  2132. if(!empty($item['clerk_code'])){
  2133. $clerk_code = $item['clerk_code'];
  2134. $clerk_code_pre = $clerk_code[0] . $clerk_code[1];
  2135. if($clerk_code_pre!=ClerkEnum::RESERVATION_SERVICE_CLERK_CODE_PRE){
  2136. $clerk_code = OrderReserve::getClerkCode($item['mall_id'],ClerkEnum::RESERVATION_SERVICE_CLERK_CODE_PRE);
  2137. $item->clerk_code = $clerk_code;
  2138. $item->save();
  2139. Order::updateAll(['clerk_code'=>$clerk_code],['order_no'=>$item['order_no']]);
  2140. $order = Order::findOne(['order_no'=>$item['order_no']]);
  2141. OrderReserve::updateAll(['reserve_code'=>$clerk_code],['order_id'=>$order['id']]);
  2142. StoreOrderReserve::updateAll(['reserve_code'=>$clerk_code],['order_id'=>$item['id'],'main_order_id'=>$order['id']]);
  2143. }
  2144. }
  2145. }
  2146. $offset++;
  2147. }
  2148. }
  2149. }