StoreCommission.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. <?php
  2. namespace addons\Store\common\models;
  3. use common\components\export\CsvTool;
  4. use common\enums\DownloadEnum;
  5. use common\enums\StatusEnum;
  6. use common\models\base\BaseActiveRecord;
  7. use common\models\common\Download;
  8. use common\models\user\User;
  9. use common\services\mall\ExportService;
  10. use Yii;
  11. /**
  12. * This is the model class for table "qimall_addons_store_commission".
  13. *
  14. * @property int $id
  15. * @property int $mall_id 商城id
  16. * @property int $store_id 门店id
  17. * @property int $user_id 会员id
  18. * @property string $order_no 订单编号
  19. * @property float $order_money 订单金额
  20. * @property float $pay_money 支付金额
  21. * @property float $discount_money 优惠金额
  22. * @property float $addons_bonus 插件分红
  23. * @property float $service_charge 服务费
  24. * @property float $amount_received 到账金额
  25. * @property int $is_settlement 结算状态 0:待结算;1:已结算
  26. * @property int $type 类型:1:o2o订单;2:o2o收银台订单;3:门店核销奖励
  27. * @property int $created_at
  28. * @property int $updated_at
  29. * @property int|null $status 状态[-1:删除;0:禁用;1启用]
  30. * @property float $store_send_commission 门店直接发放佣金,不包含平台设置的插件佣金
  31. * @property float $higo_reward HiGo商家让利,商户嗨贝不足扣除等额到账金额
  32. * @property float $store_contributing_money 折扣金额
  33. * @property float $score_deduct_num 抵扣积分数量
  34. * @property float $amount_received_score 到账积分
  35. * @property int $score_deduction_bear 积分抵扣-优惠承担对象 -1:未开启积分抵扣;0:平台:1:门店
  36. */
  37. class StoreCommission extends BaseActiveRecord
  38. {
  39. /**
  40. * {@inheritdoc}
  41. */
  42. public static function tableName()
  43. {
  44. return '{{%addons_store_commission}}';
  45. }
  46. /**
  47. * {@inheritdoc}
  48. */
  49. public function rules()
  50. {
  51. return [
  52. [['mall_id', 'store_id', 'user_id', 'is_settlement', 'type', 'created_at', 'updated_at', 'status','settle_type','score_deduction_bear'], 'integer'],
  53. [['order_money', 'pay_money', 'discount_money', 'addons_bonus', 'service_charge', 'amount_received','store_send_commission', 'higo_reward','store_contributing_money','store_agent_send_commission',
  54. 'amount_received_score','score_deduct_num'], 'number'],
  55. [['order_no'], 'string', 'max' => 100],
  56. ];
  57. }
  58. /**
  59. * {@inheritdoc}
  60. */
  61. public function attributeLabels()
  62. {
  63. return [
  64. 'id' => 'ID',
  65. 'mall_id' => '商城id',
  66. 'store_id' => '门店id',
  67. 'user_id' => '会员id',
  68. 'order_no' => '订单编号',
  69. 'order_money' => '订单金额',
  70. 'pay_money' => '支付金额',
  71. 'discount_money' => '优惠金额',
  72. 'addons_bonus' => '插件分红',
  73. 'service_charge' => '服务费',
  74. 'amount_received' => '到账金额',
  75. 'is_settlement' => '结算状态 0:待结算;1:已结算',
  76. 'settle_type' => '1,2,3平台承担,4门店承担',
  77. 'type' => '类型:1:o2o订单;2:o2o收银台订单',
  78. 'created_at' => 'Created At',
  79. 'updated_at' => 'Updated At',
  80. 'status' => '状态[-1:删除;0:禁用;1启用]',
  81. 'store_send_commission' => '门店直接发放佣金',
  82. 'higo_reward' => 'HiGo商家让利,商户嗨贝不足扣除等额到账金额',
  83. 'store_contributing_money' => '折扣金额',
  84. 'amount_received_score' => '到账积分',
  85. 'score_deduct_num' => '抵扣积分数量',
  86. 'score_deduction_bear' => '积分抵扣-优惠承担对象 -1:未开启积分抵扣;0:平台:1:门店'
  87. ];
  88. }
  89. public function getUser()
  90. {
  91. return $this->hasOne(User::class, ['id' => 'user_id']);
  92. }
  93. public function getStore()
  94. {
  95. return $this->hasOne(Store::class, ['id' => 'store_id'])->select('id, shop_mobile, store_name');
  96. }
  97. public static function setData(array $params)
  98. {
  99. try {
  100. $model = new self();
  101. $model->loadDefaultValues();
  102. if (!$model->load($params, '') || !$model->save()) {
  103. throw new \Exception($model->getErrorMessage());
  104. }
  105. return $model;
  106. } catch (\Exception $e) {
  107. self::$static_error = $e->getMessage() . $e->getLine() . $e->getFile();
  108. return false;
  109. }
  110. }
  111. /**
  112. * @name:
  113. * @msg: 数据导出处理器
  114. * @param {*} $data
  115. * @return {*}
  116. */
  117. public static function exportHandle(array $data = null)
  118. {
  119. try {
  120. $download_id = $data['download_id'] ?? 0;
  121. $download = Download::findOne(['id' => $download_id]);
  122. $params = json_decode($download->params, true);
  123. // dd($params);
  124. $have_select_field_arr = [];
  125. $all_fields = self::fieldsList();
  126. $fields = $params['fields'] ?? [];
  127. if (!empty($fields)) {
  128. foreach ($fields as $field) {
  129. $have_select_field_arr[] = $all_fields[$field];
  130. }
  131. } else {
  132. $have_select_field_arr = $all_fields;
  133. }
  134. // dd($have_select_field_arr);
  135. $csv = new CsvTool();
  136. $csv->filename = $download->name;
  137. $csv->file_dirname = DownloadEnum::getTypeStorageDirMap($download->type);
  138. $csv->export_mode = CsvTool::EXPORT_MODE_ASYNC;
  139. $csv->header = $have_select_field_arr;
  140. // if (!empty($fields)) {
  141. // $select = $fields;
  142. // // $select = array_merge($select, ['user_id', 'store_id']);
  143. // } else {
  144. // $select = '*';
  145. // }
  146. $list_query = self::find()->where(['mall_id' => $params['mall_id'], 'status' => StatusEnum::ENABLED]);
  147. if (!empty($min_amount)) {
  148. $list_query->andWhere(['>=', 'pay_money', $min_amount]);
  149. }
  150. if (!empty($max_amount)) {
  151. $list_query->andWhere(['<=', 'pay_money', $max_amount]);
  152. }
  153. if (!empty($start_time)) {
  154. $list_query->andWhere(['>=', 'created_at', $start_time]);
  155. }
  156. if (!empty($end_time)) {
  157. $list_query->andWhere(['<=', 'created_at', $end_time]);
  158. }
  159. if (!empty($store_name)) {
  160. $stores = Store::find()
  161. ->select('id,store_name,logo_img')
  162. ->where(['mall_id' => $params['mall_id'], 'status' => StatusEnum::ENABLED])
  163. ->andWhere(['like', 'store_name', $store_name])
  164. ->asArray()
  165. ->indexBy('id')
  166. ->all();
  167. $store_ids = array_column($stores, 'id');
  168. $list_query->andWhere(['store_id' => $store_ids]);
  169. }
  170. if (!empty($user_id)) {
  171. $list_query->andWhere(['user_id' => $user_id]);
  172. }
  173. $user_wheres = [];
  174. $users = [];
  175. if (!empty($nickname)) {
  176. $user_wheres[] = ['like', 'nickname', $nickname];
  177. }
  178. if (!empty($mobile)) {
  179. $user_wheres[] = ['like', 'mobile', $mobile];
  180. }
  181. if (!empty($user_wheres)) {
  182. $user_wheres[] = ['mall_id' => $params['mall_id'], 'status' => StatusEnum::ENABLED];
  183. $query = User::find()->select('id,nickname,mobile,avatar_url');
  184. foreach ($user_wheres as $where) {
  185. $query->andWhere($where);
  186. }
  187. $users = $query->asArray()->indexBy('id')->all();
  188. $user_ids = array_column($users, 'id');
  189. $list_query->andWhere(['user_id' => $user_ids]);
  190. }
  191. $rows = [];
  192. foreach ($list_query->asArray()->batch(200) as $lists) {
  193. // dd($lists);
  194. if (empty($users)) {
  195. $user_ids = array_column($lists, 'user_id');
  196. $users = User::find()
  197. ->select('id,nickname,mobile,avatar_url')
  198. ->where(['mall_id' => $params['mall_id'], 'status' => StatusEnum::ENABLED, 'id' => $user_ids])
  199. ->asArray()
  200. ->indexBy('id')
  201. ->all();
  202. }
  203. if (empty($stores)) {
  204. $store_ids = array_column($lists, 'store_id');
  205. $stores = Store::find()
  206. ->select('id,store_name,logo_img')
  207. ->where(['mall_id' => $params['mall_id'], 'status' => StatusEnum::ENABLED, 'id' => $store_ids])
  208. ->asArray()
  209. ->indexBy('id')
  210. ->all();
  211. }
  212. foreach ($lists as $list) {
  213. $user = $users[$list['user_id']] ?? '';
  214. $store = $stores[$list['store_id']] ?? '';
  215. $list['nickname'] = $user['nickname'] ?? '';
  216. $list['mobile'] = $user['mobile'] ?? '';
  217. $list['store_name'] = $store['store_name'] ?? '';
  218. // dd($list);
  219. $arr = [];
  220. foreach ($fields as $field) {
  221. if (!empty($list[$field])) {
  222. if ('created_at' == $field) {
  223. $list[$field] = date('Y-m-d H:i:s', $list[$field]);
  224. }
  225. if ('mobile' == $field) {
  226. $list[$field] = (string)$list[$field];
  227. }
  228. } else {
  229. $list[$field] = '';
  230. }
  231. $arr[] = $list[$field];
  232. }
  233. $rows[] = $arr;
  234. }
  235. }
  236. $csv->data = $rows;
  237. $csv->export();
  238. $csv->updateDown($download, $params['mall_id']);
  239. return true;
  240. } catch (\Exception $e) {
  241. $download->status = 3;
  242. $res = $download->save();
  243. self::setStaticError($e->getMessage());
  244. return $e->getMessage();
  245. }
  246. }
  247. /**
  248. * 订单详情导出
  249. * @param array $data
  250. * @return string|true
  251. */
  252. public static function orderDetailExportHandle(array $data)
  253. {
  254. $download_id = $data['download_id'] ?? 0;
  255. $download = Download::findOne(['id' => $download_id]);
  256. $transaction = \Yii::$app->db->beginTransaction();
  257. try {
  258. $params = json_decode($download->params, true);
  259. $fileName = $download->name;
  260. $storeModel = self::find()->where(['mall_id' => $params['mall_id'], 'status' => StatusEnum::ENABLED, 'type' => 1]);
  261. if (!empty($params['store_name'])) {
  262. $store_ids = Store::find()
  263. ->select('id')
  264. ->where(['mall_id' => $params['mall_id'], 'status' => StatusEnum::ENABLED])
  265. ->andWhere(['like', 'store_name', $params['store_name']])
  266. ->asArray()
  267. ->indexBy('id')
  268. ->column();
  269. $storeModel->andWhere(['store_id' => $store_ids]);
  270. }
  271. $user_ids = [];
  272. if (!empty($params['user_id'])) {
  273. $user_ids[] = $params['user_id'];
  274. }
  275. if (!empty($params['nickname'])) {
  276. $user_ids = array_merge($user_ids, self::getUserIdsByParams($params, 'nickname'));
  277. }
  278. if (!empty($params['mobile'])) {
  279. $user_ids = array_merge($user_ids, self::getUserIdsByParams($params, 'mobile'));
  280. }
  281. if (!empty($user_ids)) {
  282. $storeModel->andWhere(['user_id' => $user_ids]);
  283. }
  284. if (!empty($params['order_no'])) {
  285. $storeModel->andWhere(['like', 'order_no', $params['order_no']]);
  286. }
  287. if (!empty($params['order_status'])) {
  288. switch ($params['order_status']) {
  289. case 1:
  290. $storeModel->andWhere(['is_settlement' => 0]);
  291. break;
  292. case 2:
  293. $storeModel->andWhere(['is_settlement' => 1]);
  294. break;
  295. default:
  296. $storeModel->andWhere(['!=', 'status', StatusEnum::ENABLED]);
  297. }
  298. }
  299. if (!empty($params['order_ids'])) {
  300. $storeModel->andWhere(['id' => $params['order_ids']]);
  301. }
  302. $batchSize = 10000;
  303. $totalRecords = $storeModel->count() ?? 0;
  304. $is_model_page = bcdiv($totalRecords, $batchSize);
  305. $oldFields = $params['fields'] ?? [];
  306. $exportHeader = [];
  307. $fields = [];
  308. $orderDetailFieldsList = self::orderDetailFieldsList();
  309. foreach ($orderDetailFieldsList as $field => $fieldName)
  310. {
  311. if (in_array($field, $oldFields)) {
  312. $fields[] = $field;
  313. $exportHeader[] = $fieldName;
  314. }
  315. }
  316. $whereWith = ['store', 'user' => function ($query) {
  317. $query->select('id, nickname, mobile, avatar_url');
  318. }];
  319. $i = 0;
  320. foreach ($storeModel->with($whereWith)->orderBy('id desc')->asArray()->batch($batchSize) as $stores) {
  321. $exportList = [];
  322. foreach ($stores as $store) {
  323. $exportItem = self::buildExportItem($store, $fields);
  324. $exportList[] = $exportItem;
  325. }
  326. if (!empty($exportList)) {
  327. $csv = new CsvTool();
  328. $csv->header = $exportHeader;
  329. $csv->file_dirname = DownloadEnum::getTypeStorageDirMap($download->type);
  330. $csv->export_mode = CsvTool::EXPORT_MODE_ASYNC;
  331. $csv->data = $exportList;
  332. $csv->filename = $is_model_page ? $fileName . '_1' : $fileName;
  333. if ($is_model_page && $i == 0) { // 因为订单页需要分页,所以需要设置文件名
  334. $download->name = $fileName . '_1';
  335. $download->save();
  336. }
  337. if ($i >= 1) {
  338. $newFileName = $fileName . '_' . ($i + 1);
  339. $csv->filename = $newFileName;
  340. $downloadData = [
  341. 'mall_id' => $download->mall_id,
  342. 'mch_id' => $download->mch_id,
  343. 'store_id' => $download->store_id,
  344. 'name' => $newFileName,
  345. 'type' => $download->type,
  346. 'handler_class' => $download->handler_class,
  347. 'method' => $download->method,
  348. 'params' => $download->params,
  349. 'data' => $exportList
  350. ];
  351. $downloadModel = Download::setData($downloadData);
  352. if ($downloadModel === false) {
  353. Yii::$app->custom->logs('创建下载任务失败:' . $downloadData['name'], Download::getStaticError());
  354. throw new \Exception('创建新下载任务失败');
  355. };
  356. $download = $downloadModel;
  357. }
  358. $csv->export();
  359. $csv->updateDown($download, $params['mall_id']);
  360. $i++;
  361. }
  362. unset($exportList);
  363. }
  364. $transaction->commit();// 事务完成
  365. return true;
  366. } catch (\Exception $e) {
  367. $transaction->rollBack();
  368. $download->status = 3;
  369. $res = $download->save();
  370. self::setStaticError($e->getMessage());
  371. return $e->getMessage();
  372. }
  373. }
  374. /**
  375. * 构建导出数据
  376. * @param $store
  377. * @param $fields
  378. * @return array
  379. */
  380. public static function buildExportItem($store, $fields): array
  381. {
  382. $exportItem = [];
  383. foreach ($fields as $field) {
  384. switch ($field) {
  385. case 'store_name':
  386. $exportItem[$field] = $store['store']['store_name'] ?? '';
  387. break;
  388. case 'user_id':
  389. $exportItem[$field] = $store['user_id'] ?? '';
  390. break;
  391. case 'nickname':
  392. $exportItem[$field] = $store['user']['nickname'] ?? '';
  393. break;
  394. case 'mobile':
  395. $exportItem[$field] = $store['user']['mobile'] ?? '';
  396. break;
  397. case 'order_no':
  398. $exportItem[$field] = $store['order_no'] ?? '';
  399. break;
  400. case 'order_money':
  401. $exportItem[$field] = $store['order_money'] ?? '';
  402. break;
  403. case 'discount_money':
  404. $exportItem[$field] = $store['discount_money'] ?? '';
  405. break;
  406. case 'pay_money':
  407. $exportItem[$field] = $store['pay_money'] ?? '';
  408. break;
  409. case 'addons_bonus':
  410. $exportItem[$field] = $store['addons_bonus'] ?? '';
  411. break;
  412. case 'store_send_commission':
  413. $exportItem[$field] = $store['store_send_commission'] ?? '';
  414. break;
  415. case 'service_charge':
  416. $exportItem[$field] = $store['service_charge'] ?? '';
  417. break;
  418. case 'amount_received':
  419. $exportItem[$field] = $store['amount_received'] ?? '';
  420. break;
  421. case 'is_settlement':
  422. $exportItem[$field] = $store['is_settlement'] == 1 ? '已结算' : '未结算';
  423. break;
  424. case 'created_at':
  425. $exportItem[$field] = date('Y-m-d H:i:s', $store['created_at']);
  426. break;
  427. }
  428. }
  429. return $exportItem;
  430. }
  431. /**
  432. * 根据查询条件获取用户ID
  433. * @param $params
  434. * @param $field
  435. * @return array
  436. */
  437. public static function getUserIdsByParams($params, $field): array
  438. {
  439. if (empty($params[$field])) {
  440. return [];
  441. }
  442. try {
  443. return User::find()
  444. ->select('id')
  445. ->where(['mall_id' => $params['mall_id'], 'status' => StatusEnum::ENABLED])
  446. ->andWhere(['like', $field, $params[$field]])
  447. ->asArray()
  448. ->column();
  449. } catch (\Exception $e) {
  450. // 记录异常日志
  451. \Yii::error("Failed to query user IDs by $field: " . $e->getMessage());
  452. return [];
  453. }
  454. }
  455. public static function fieldsList(array $fields = []): array
  456. {
  457. $field_list = [
  458. 'store_name' => '门店名称',
  459. 'nickname' => '会员昵称',
  460. 'mobile' => '会员手机号',
  461. 'order_no' => '订单编号',
  462. 'order_money' => '应付金额',
  463. 'pay_money' => '实付金额',
  464. 'discount_money' => '优惠金额',
  465. 'amount_received' => '实收金额',
  466. 'created_at' => '下单时间',
  467. ];
  468. if (empty($fields)) {
  469. return $field_list;
  470. } else {
  471. $new_list = [];
  472. foreach ($fields as $val) {
  473. if (!empty($field_list[$val])) {
  474. $new_list[$val] = $fields[$val];
  475. }
  476. }
  477. return $new_list;
  478. }
  479. }
  480. /**
  481. * 资产管理-订单明细导出
  482. * @param array $fields
  483. * @return array
  484. */
  485. public static function orderDetailFieldsList(array $fields = []): array
  486. {
  487. return [
  488. 'store_name' => '门店名称',
  489. 'user_id' => '用户ID',
  490. 'nickname' => '用户昵称',
  491. 'mobile' => '用户手机号',
  492. 'order_no' => '订单编号',
  493. 'order_money' => '订单金额',
  494. 'discount_money' => '优惠金额',
  495. 'pay_money' => '实付金额',
  496. 'addons_bonus' => '插件分红',
  497. 'store_send_commission' => '门店股东分红',
  498. 'service_charge' => '服务费',
  499. 'amount_received' => '到账金额',
  500. 'is_settlement' => '状态',
  501. 'created_at' => '创建时间',
  502. ];
  503. }
  504. }