CustomClass.php 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368
  1. <?php
  2. namespace bizHd\custom\classes;
  3. use biz\wx\classes\WxMessageClass;
  4. use bizHd\balance\classes\BalanceChangeClass;
  5. use bizHd\balance\classes\BalanceGiveChangeClass;
  6. use bizHd\balance\classes\BalancePayChangeClass;
  7. use bizHd\birthday\classes\BirthdayGiftClass;
  8. use bizHd\distribution\classes\DistributionUserClass;
  9. use bizHd\hb\classes\HbAutoRuleClass;
  10. use bizHd\hb\models\HbAutoRule;
  11. use bizHd\member\classes\MemberChangeClass;
  12. use bizHd\member\classes\MemberLevelClass;
  13. use bizHd\order\classes\OrderClass;
  14. use bizHd\order\classes\SettleClass;
  15. use bizHd\shop\classes\ShopClass;
  16. use bizHd\user\classes\UserClass;
  17. use bizHd\user\classes\UserGrowthClass;
  18. use common\components\dict;
  19. use common\components\imgUtil;
  20. use common\components\noticeUtil;
  21. use common\components\stringUtil;
  22. use common\components\util;
  23. use Overtrue\ChineseCalendar\Calendar;
  24. use bizHd\base\classes\BaseClass;
  25. use Yii;
  26. class CustomClass extends BaseClass
  27. {
  28. public static $baseFile = '\bizHd\custom\models\Custom';
  29. public static function getBalanceStat($where)
  30. {
  31. $cacheKey = self::getBalanceStatCacheKey($where);
  32. $cached = \Yii::$app->redis->executeCommand('GET', [$cacheKey]);
  33. if ($cached !== false && $cached !== null && $cached !== '') {
  34. $data = json_decode($cached, true);
  35. if (is_array($data)) {
  36. return $data;
  37. }
  38. }
  39. $countWhere = array_merge($where, ['balance>' => 0]);
  40. $count = self::getCount($countWhere);
  41. $totalBalance = self::sum($where, 'balance');
  42. $data = [
  43. 'count' => intval($count),
  44. 'totalBalance' => bcadd($totalBalance ?: '0', '0', 2),
  45. ];
  46. \Yii::$app->redis->executeCommand('SETEX', [$cacheKey, 60, json_encode($data)]);
  47. return $data;
  48. }
  49. public static function getBalanceStatCacheKey($where)
  50. {
  51. return 'hd_custom_balance_stat:' . md5(json_encode($where, JSON_UNESCAPED_UNICODE));
  52. }
  53. /**
  54. * 修改客户生日
  55. * @param $customId
  56. * @param $shopId
  57. * @param $params
  58. * @return array [custom, bool] custom表示客户数据,bool表示是否变动了生日
  59. * @throws \Exception
  60. */
  61. public static function modifyBirthday($customId, $shopId, $params)
  62. {
  63. date_default_timezone_set('PRC');
  64. $custom = self::getById($customId, true);
  65. if (empty($custom)) {
  66. util::fail('没有找到客户');
  67. }
  68. if ($custom->shopId != $shopId) {
  69. util::fail('不是你的客户');
  70. }
  71. $lunar = $params['lunar'] ?? 0;
  72. $birthdayMonth = $params['birthdayMonth'] ?? 1;
  73. if ($birthdayMonth > 12 || $birthdayMonth < 1) {
  74. util::fail('月份必须1到12月');
  75. }
  76. $birthdayDate = $params['birthdayDate'] ?? 1;
  77. if ($birthdayDate > 31 || $birthdayDate < 1) {
  78. util::fail('日期必须1到31号');
  79. }
  80. $userId = $custom->userId;
  81. $user = UserClass::getById($userId, true);
  82. if (empty($user)) {
  83. util::fail('客户信息缺失');
  84. }
  85. if ($lunar == 1 && $birthdayDate == 31) {
  86. util::fail('农历没有31号');
  87. }
  88. $isUpdateBirthday = $user->birthdayTime == 0;
  89. // 如果 xhUser 中已经设置了生日,则直接取用
  90. if ($user->birthdayTime != 0) {
  91. $custom->lunar = $user->lunar;
  92. $custom->birthdayDate = $user->birthdayDate;
  93. $custom->birthdayMonth = $user->birthdayMonth;
  94. $custom->birthday = $user->birthday;
  95. $custom->birthdayTime = $user->birthdayTime;
  96. $custom->save();
  97. } else {
  98. $calendar = new Calendar();
  99. if ($lunar == 1) {
  100. try {
  101. $result = $calendar->lunar(date("Y"), $birthdayMonth, $birthdayDate);
  102. } catch (\InvalidArgumentException $e) {
  103. $msg = $e->getMessage();
  104. util::fail($msg);
  105. }
  106. //农历转阳历,有多处使用,需要同步修改,关键词 change_my_birthday
  107. $month = $result['gregorian_month'] ?? 1;
  108. $date = $result['gregorian_day'] ?? 1;
  109. $birthday = date("Y") . '-' . $month . '-' . $date;
  110. } else {
  111. $birthday = date("Y") . '-' . $birthdayMonth . '-' . $birthdayDate;
  112. }
  113. $birthdayTime = strtotime($birthday);
  114. if (getenv('YII_ENV') != 'dev' && $user->birthdaySet == 1) {
  115. util::fail('客户已填写,不能修改');
  116. }
  117. $custom->lunar = $lunar;
  118. $custom->birthdayDate = $birthdayDate;
  119. $custom->birthdayMonth = $birthdayMonth;
  120. $custom->birthday = $birthday;
  121. $custom->birthdayTime = $birthdayTime;
  122. $custom->save();
  123. $user->lunar = $lunar;
  124. $user->birthdayDate = $birthdayDate;
  125. $user->birthdayMonth = $birthdayMonth;
  126. $user->birthday = $birthday;
  127. $user->birthdayTime = $birthdayTime;
  128. $user->save();
  129. }
  130. // 同步变更生日赠礼记录表(xhBirthdayGift)中的数据(只更新当年年份的,往年的不去修改)
  131. $birthdayGift = BirthdayGiftClass::getByCondition(['userId'=>$user->id, 'shopId'=>$shopId, 'year'=>date("Y")], true);
  132. if (!empty($birthdayGift)) {
  133. $lunar = intval($custom->lunar);
  134. $birthdayMonth = intval($custom->birthdayMonth);
  135. $birthdayDate = intval($custom->birthdayDate);
  136. list($giftBirthdayMonth, $giftBirthdayDate) = BirthdayGiftClass::convertBirthdayMonthDay(
  137. $lunar,
  138. $birthdayMonth,
  139. $birthdayDate
  140. );
  141. $birthdayGift->lunar = $lunar;
  142. $birthdayGift->birthdayMonth = $giftBirthdayMonth;
  143. $birthdayGift->birthdayDate = $giftBirthdayDate;
  144. $birthdayGift->birthdayDisplay = BirthdayGiftClass::formatBirthdayDisplay($custom, $giftBirthdayMonth, $giftBirthdayDate);
  145. $birthdayGift->status = 1;
  146. $birthdayGift->save();
  147. }
  148. return [$custom, $isUpdateBirthday];
  149. }
  150. //用余额支付,客户余额减少 ssh 20250410
  151. public static function payToChangeBalance($order)
  152. {
  153. $actPrice = $order->actPrice ?? 0;
  154. $hdId = $order->hdId ?? 0;
  155. $hd = HdClass::getLockById($hdId);
  156. $balance = $hd->balance ?? 0;
  157. if ($actPrice > $balance) {
  158. util::fail('余额不足');
  159. }
  160. $remain = bcsub($balance, $actPrice, 2);
  161. $hd->balance = $remain;
  162. $hd->save();
  163. $hdName = $hd->name;
  164. $customId = $order->customId ?? 0;
  165. $custom = self::getLockById($customId);
  166. $balance = $custom->balance ?? 0;
  167. if ($actPrice > $balance) {
  168. util::fail('余额不足哦');
  169. }
  170. $remain = bcsub($balance, $actPrice, 2);
  171. $custom->balance = $remain;
  172. $custom->save();
  173. $customName = $custom->name;
  174. if ($custom->balance != $hd->balance) {
  175. util::fail('余额有问题哦');
  176. }
  177. $relateId = $order->id ?? 0;
  178. //0 花店操作 1 客户操作
  179. $payWay = $order->payWay;
  180. $side = 1;
  181. $shopId = $order->shopId;
  182. $mainId = $order->mainId;
  183. $staffId = $order->shopAdminId;
  184. $staffName = $order->shopAdminName;
  185. $orderSn = $order->orderSn;
  186. $event = '买花,单号:' . $orderSn;
  187. $capitalType = dict::getDict('capitalType', 'xhOrder', 'id');
  188. $change = [
  189. 'hdId' => $hdId,
  190. 'hdName' => $hdName,
  191. 'customId' => $customId,
  192. 'customName' => $customName,
  193. 'relateId' => $relateId,
  194. 'onlinePay' => 1,
  195. 'capitalType' => $capitalType,
  196. 'amount' => $actPrice,
  197. 'balance' => $hd->balance,
  198. 'io' => 0,
  199. 'side' => $side,
  200. 'payWay' => $payWay,
  201. 'event' => $event,
  202. 'staffId' => $staffId,
  203. 'staffName' => $staffName,
  204. 'shopId' => $shopId,
  205. 'mainId' => $mainId,
  206. 'remark' => '',
  207. ];
  208. BalanceChangeClass::add($change, true);
  209. $order->balance = $actPrice;
  210. $order->save();
  211. // 多处需要同步修改 balance_pay_give
  212. if ($hd->balancePay >= $actPrice) {
  213. $payAmount = $actPrice;
  214. $mustUseGiveAmount = 0;
  215. } else {
  216. $payAmount = $hd->balancePay;
  217. $mustUseGiveAmount = bcsub($actPrice, $payAmount, 2);
  218. if ($mustUseGiveAmount > $hd->balanceGive) {
  219. util::fail('赠送余额异常,不够扣');
  220. }
  221. }
  222. /************************* 使用充值余额 *****************************/
  223. $customBalancePay = bcsub($custom->balancePay, $payAmount, 2);
  224. $custom->balancePay = $customBalancePay;
  225. $custom->save();
  226. $hdBalancePay = bcsub($hd->balancePay, $payAmount, 2);
  227. $hd->balancePay = $hdBalancePay;
  228. $hd->save();
  229. $payChange = [
  230. 'hdId' => $hdId,
  231. 'hdName' => $hdName,
  232. 'customId' => $customId,
  233. 'customName' => $customName,
  234. 'relateId' => $relateId,
  235. 'onlinePay' => 1,
  236. 'capitalType' => $capitalType,
  237. 'amount' => $payAmount,
  238. 'balance' => $customBalancePay,
  239. 'io' => 0,
  240. 'side' => $side,
  241. 'payWay' => $payWay,
  242. 'event' => $event,
  243. 'staffId' => $staffId,
  244. 'staffName' => $staffName,
  245. 'shopId' => $shopId,
  246. 'mainId' => $mainId,
  247. 'remark' => '',
  248. ];
  249. BalancePayChangeClass::add($payChange, true);
  250. $order->payBalance = $payAmount;
  251. $order->save();
  252. /***************************** 使用赠送余额 ******************************/
  253. //应用掉的赠送金额
  254. if ($mustUseGiveAmount > 0) {
  255. $customBalanceGive = bcsub($custom->balanceGive, $mustUseGiveAmount, 2);
  256. if ($customBalanceGive < 0) {
  257. util::fail('余额异常哈!请联系管理员,编号' . $hdId . ' ' . $custom->balanceGive);
  258. }
  259. $custom->balanceGive = $customBalanceGive;
  260. $custom->save();
  261. $hdBalanceGive = bcsub($hd->balanceGive, $mustUseGiveAmount, 2);
  262. $hd->balanceGive = $hdBalanceGive;
  263. $hd->save();
  264. if (floatval($customBalanceGive) != floatval($hdBalanceGive)) {
  265. util::fail('余额有问题呢!请联系管理员,编号' . $hdId);
  266. }
  267. $giveChange = [
  268. 'hdId' => $hdId,
  269. 'hdName' => $hdName,
  270. 'customId' => $customId,
  271. 'customName' => $customName,
  272. 'relateId' => $relateId,
  273. 'onlinePay' => 1,
  274. 'capitalType' => $capitalType,
  275. 'amount' => $mustUseGiveAmount,
  276. 'balance' => $customBalanceGive,
  277. 'io' => 0,
  278. 'side' => $side,
  279. 'payWay' => $payWay,
  280. 'event' => $event,
  281. 'staffId' => $staffId,
  282. 'staffName' => $staffName,
  283. 'shopId' => $shopId,
  284. 'mainId' => $mainId,
  285. 'remark' => '',
  286. ];
  287. BalanceGiveChangeClass::add($giveChange, true);
  288. $order->giveBalance = $mustUseGiveAmount;
  289. $order->save();
  290. }
  291. $addBalance = bcadd($hd->balancePay, $hd->balanceGive, 2);
  292. if (floatval($addBalance) != floatval($custom->balance)) {
  293. util::fail('账户余额有问题!请检查,编号' . $customId);
  294. }
  295. }
  296. //会员等级变化,包括手动修改、自动降会员和充值升会员等 ssh 20250324
  297. public static function levelChange($oldLevel, $newLevel, $shop, $custom, $hd, $params)
  298. {
  299. $adminId = $params['adminId'];
  300. $staffId = $params['staffId'] ?? 0;
  301. $staffName = $params['staffName'] ?? '';
  302. $style = $params['style'] ?? 0;
  303. $target = $params['target'] ?? [];
  304. $rechargeAmount = $params['rechargeAmount'] ?? 0;
  305. $targetId = $target->id ?? 0;
  306. $mainId = $shop->mainId;
  307. $shopId = $shop->id;
  308. $levelData = MemberLevelClass::getAllByCondition(['mainId' => $mainId], null, '*', 'level');
  309. $current = $levelData[$newLevel] ?? [];
  310. $before = $levelData[$oldLevel] ?? [];
  311. $beforeName = $before['name'] ?? '普通客户';
  312. $discount = $current['discount'] ? $current['discount'] / 10 : 1;
  313. $memberName = $current['name'] ?? '';
  314. $oldGrowth = $custom->growth;
  315. $hd->member = $newLevel;
  316. $hd->discount = $discount;
  317. $hd->memberName = $memberName;
  318. $hd->save();
  319. $event = '手动修改';
  320. if ($style == 0) {
  321. util::fail('充值不支持升级会员');
  322. }
  323. $change = [
  324. 'customId' => $custom->id,
  325. 'customName' => $custom->name,
  326. 'hdId' => $hd->id,
  327. 'hdName' => $hd->name,
  328. 'mainId' => $mainId,
  329. 'shopId' => $shopId,
  330. 'targetId' => $targetId,
  331. 'rechargeAmount' => $rechargeAmount,
  332. 'days' => 0,
  333. 'daysBefore' => '0000-00-00 00:00:00',
  334. 'daysAfter' => '0000-00-00 00:00:00',
  335. 'beforeLevel' => $oldLevel,
  336. 'afterLevel' => $newLevel,
  337. 'beforeName' => $beforeName,
  338. 'afterName' => $memberName,
  339. 'style' => $style,
  340. 'event' => $event,
  341. 'staffId' => $staffId,
  342. 'staffName' => $staffName,
  343. ];
  344. MemberChangeClass::add($change);
  345. $custom->member = $newLevel;
  346. $custom->discount = $discount;
  347. $custom->memberName = $memberName;
  348. //成长值变更
  349. $growth = $current['amount'] ?? 0;
  350. $custom->growth = $growth;
  351. $custom->save();
  352. //成长值变动记录
  353. $growthData = [
  354. 'shopId' => $shopId,
  355. 'userId' => $custom->userId,
  356. 'userName' => $custom->name,
  357. 'event' => "管理员变更{$memberName}级,成长值从{$oldGrowth}变更为{$growth}",
  358. 'relateId' => 0,
  359. 'relateType' => 0,
  360. 'num' => $custom->growth - $oldGrowth,
  361. 'growth' => $growth,
  362. //'operatorId' => $adminId,
  363. 'staffId' => $staffId, //操作人(员工id)
  364. 'staffName' => $staffName, //员工名称
  365. 'createTime' => date('Y-m-d H:i:s')
  366. ];
  367. UserGrowthClass::add($growthData);
  368. }
  369. //客户采购欠款金额增加,如果有余额时,要进行欠款销账 ssh 20250715
  370. //这边开欠款单时,如果还有余额,会产生结账动作,结账动作也可以用赠送余额来结账,所以要分出赠送余额的占比
  371. //结账消余额,不是下单时消余额,不涉及售后时余额回滚问题,所以不需要设置 xhOrder 的 giveBalance payBalance balance等值
  372. public static function skCgDebtAmountAdd($custom, $order)
  373. {
  374. $clearAmount = 0;
  375. $amount = $order->remainDebtPrice ?? 0;
  376. $staffId = $order->shopAdminId ?? 0;
  377. $staffName = $order->shopAdminName ?? '';
  378. $orderId = $order->id;
  379. $orderSn = $order->orderSn ?? '';
  380. $shopId = $order->shopId;
  381. $settleNo = '';
  382. $settleId = 0;
  383. $settleAmount = 0;
  384. $hdId = $custom->hdId ?? 0;
  385. $hd = HdClass::getLockById($hdId);
  386. if (empty($hd)) {
  387. util::fail('花店信息缺失,编号6325');
  388. }
  389. $hdName = $hd->name ?? '';
  390. //结账时用了多少赠送的余额
  391. $settleUseGiveAmount = 0;
  392. if ($custom->balance > 0) {
  393. if ($amount > $custom->balance) {
  394. $clearAmount = $custom->balance;
  395. $settleUseGiveAmount = $custom->balanceGive;
  396. } else {
  397. util::fail('余额充足,请用余额支付');
  398. }
  399. }
  400. if ($clearAmount > 0) {
  401. $shop = ShopClass::getById($shopId, true);
  402. $needClearIdMap[] = ['orderId' => $orderId, 'clearAmount' => $clearAmount, 'orderSn' => $orderSn];
  403. $setParams = ['staffId' => $staffId, 'staffName' => $staffName];
  404. $set = SettleClass::addSettle($needClearIdMap, $shop, $custom, $hd, $setParams);
  405. $ret = SettleClass::clearSettle($set);
  406. $settleAmount = $ret['totalClearAmount'] ?? 0;
  407. $settleNo = $set->orderSn ?? '';
  408. $settleId = $set->id;
  409. $newSettle = $ret['settle'];
  410. //结账时用了多少赠送的余额
  411. $newSettle->giveBalance = bcadd($newSettle->giveBalance, $settleUseGiveAmount, 2);
  412. $newSettle->save();
  413. }
  414. /************************ 总余额 *********************************/
  415. $customBalance = bcsub($custom->balance, $amount, 2);
  416. $custom->balance = $customBalance;
  417. if ($custom->balance < 0) {
  418. $custom->isDebt = 1;
  419. }
  420. $custom->save();
  421. $hdBalance = bcsub($hd->balance, $amount, 2);
  422. $hd->balance = $hdBalance;
  423. if ($hd->balance < 0) {
  424. $hd->debt = 2;
  425. }
  426. $hd->save();
  427. if (floatval($customBalance) != floatval($hdBalance)) {
  428. util::fail('余额有错,请联系管理员,编号' . $hdId);
  429. }
  430. $relateId = $order->id ?? 0;
  431. $customId = $custom->id ?? 0;
  432. $orderSn = $order->orderSn ?? '';
  433. $capitalType = dict::getDict('capitalType', 'xhOrder', 'id');
  434. $event = '购买花材,单号:' . $orderSn;
  435. $customName = $custom->name ?? '';
  436. $onlinePay = 1;
  437. $side = 0;
  438. $payWay = 0;
  439. $change = [
  440. 'hdId' => $hdId,
  441. 'hdName' => $hdName,
  442. 'customId' => $customId,
  443. 'customName' => $customName,
  444. 'relateId' => $relateId,
  445. 'onlinePay' => $onlinePay,
  446. 'capitalType' => $capitalType,
  447. 'amount' => $amount,
  448. 'balance' => $customBalance,
  449. 'io' => 0,
  450. 'side' => $side,
  451. 'payWay' => $payWay,
  452. 'event' => $event,
  453. 'staffId' => $staffId,
  454. 'staffName' => $staffName,
  455. 'shopId' => $shopId,
  456. 'mainId' => $order->mainId,
  457. 'settleId' => $settleId,
  458. 'settleNo' => $settleNo,
  459. 'settleAmount' => $settleAmount,
  460. 'remark' => '',
  461. ];
  462. BalanceChangeClass::add($change, true);
  463. $mustUseGiveAmount = 0;
  464. // 多处需要同步修改 balance_pay_give
  465. if ($hd->balancePay >= $amount) {
  466. util::fail('请用余额支付哈');
  467. } else {
  468. // 如果【充值金额】小于订单欠款金额,则用全部【充值金额】消单,同时必须用上【赠送金额】,够抵,则【充值金额】还是正数,不够抵,则是负数
  469. if ($hd->balanceGive <= 0) {
  470. //没有【赠送金额】,则用【充值金额】来消全部的欠款金额,不够则变成负数
  471. $payAmount = $amount;
  472. } else {
  473. //这个是【总余额】,包括【充值金额】和【赠送金额】
  474. $currentAdd = bcadd($hd->balancePay, $hd->balanceGive, 2);
  475. if ($currentAdd >= $amount) {
  476. util::fail('请使用余额支付哦');
  477. } else {
  478. //【总余额】不够抵欠款金额,先用掉全部的【赠送金额】,其他的全部算在【充值金额】名下,因为充值金额也不够扣,会出现负数
  479. $mustUseGiveAmount = $hd->balanceGive;
  480. $payAmount = bcsub($amount, $mustUseGiveAmount, 2);
  481. }
  482. }
  483. }
  484. /************************* 充值余额 *****************************/
  485. $customBalancePay = bcsub($custom->balancePay, $payAmount, 2);
  486. $custom->balancePay = $customBalancePay;
  487. $custom->save();
  488. $hdBalancePay = bcsub($hd->balancePay, $payAmount, 2);
  489. $hd->balancePay = $hdBalancePay;
  490. $hd->save();
  491. if (floatval($customBalancePay) != floatval($hdBalancePay)) {
  492. util::fail('余额有错呢,请联系管理员,编号' . $hdId);
  493. }
  494. $relateId = $order->id ?? 0;
  495. $customId = $custom->id ?? 0;
  496. $orderSn = $order->orderSn ?? '';
  497. $capitalType = dict::getDict('capitalType', 'xhOrder', 'id');
  498. $event = '购买花材,单号:' . $orderSn;
  499. $customName = $custom->name ?? '';
  500. $onlinePay = 1;
  501. $side = 0;
  502. $payWay = 0;
  503. $payChange = [
  504. 'hdId' => $hdId,
  505. 'hdName' => $hdName,
  506. 'customId' => $customId,
  507. 'customName' => $customName,
  508. 'relateId' => $relateId,
  509. 'onlinePay' => $onlinePay,
  510. 'capitalType' => $capitalType,
  511. 'amount' => $payAmount,
  512. 'balance' => $customBalancePay,
  513. 'io' => 0,
  514. 'side' => $side,
  515. 'payWay' => $payWay,
  516. 'event' => $event,
  517. 'staffId' => $staffId,
  518. 'staffName' => $staffName,
  519. 'shopId' => $shopId,
  520. 'mainId' => $order->mainId,
  521. 'settleId' => $settleId,
  522. 'settleNo' => $settleNo,
  523. 'settleAmount' => $settleAmount,
  524. 'remark' => '',
  525. ];
  526. BalancePayChangeClass::add($payChange, true);
  527. /***************************** 赠送余额 ******************************/
  528. //应用掉的赠送金额
  529. if ($mustUseGiveAmount > 0) {
  530. $customBalanceGive = bcsub($custom->balanceGive, $mustUseGiveAmount, 2);
  531. if ($customBalanceGive < 0) {
  532. util::fail('余额异常哈,请联系管理员,编号' . $hdId . ' ' . $custom->balanceGive);
  533. }
  534. $custom->balanceGive = $customBalanceGive;
  535. $custom->save();
  536. $hdBalanceGive = bcsub($hd->balanceGive, $mustUseGiveAmount, 2);
  537. $hd->balanceGive = $hdBalanceGive;
  538. $hd->save();
  539. if (floatval($customBalanceGive) != floatval($hdBalanceGive)) {
  540. util::fail('余额有问题呢,请联系管理员,编号' . $hdId);
  541. }
  542. $relateId = $order->id ?? 0;
  543. $customId = $custom->id ?? 0;
  544. $orderSn = $order->orderSn ?? '';
  545. $capitalType = dict::getDict('capitalType', 'xhOrder', 'id');
  546. $event = '购买花材,单号:' . $orderSn;
  547. $customName = $custom->name ?? '';
  548. $onlinePay = 1;
  549. $side = 0;
  550. $payWay = 0;
  551. $giveChange = [
  552. 'hdId' => $hdId,
  553. 'hdName' => $hdName,
  554. 'customId' => $customId,
  555. 'customName' => $customName,
  556. 'relateId' => $relateId,
  557. 'onlinePay' => $onlinePay,
  558. 'capitalType' => $capitalType,
  559. 'amount' => $mustUseGiveAmount,
  560. 'balance' => $customBalanceGive,
  561. 'io' => 0,
  562. 'side' => $side,
  563. 'payWay' => $payWay,
  564. 'event' => $event,
  565. 'staffId' => $staffId,
  566. 'staffName' => $staffName,
  567. 'shopId' => $shopId,
  568. 'mainId' => $order->mainId,
  569. 'settleId' => $settleId,
  570. 'settleNo' => $settleNo,
  571. 'settleAmount' => $settleAmount,
  572. 'remark' => '',
  573. ];
  574. BalanceGiveChangeClass::add($giveChange, true);
  575. }
  576. $addBalance = bcadd($hd->balancePay, $hd->balanceGive, 2);
  577. if (floatval($addBalance) != floatval($custom->balance)) {
  578. util::fail('账户余额有问题,请检查,编号' . $customId);
  579. }
  580. }
  581. /**
  582. * 隔天/无原单售后返充余额(不依赖销售单 balanceTk 拆分)
  583. * 用途:成功页「返充到客户余额」;无原单时 $order 可为空。
  584. */
  585. public static function nextDayRefundReturnBalance($custom, $amount, $refund, $order = null)
  586. {
  587. $amount = bcadd((string)$amount, '0', 2);
  588. if (bccomp($amount, '0', 2) <= 0) {
  589. util::fail('返充金额必须大于0');
  590. }
  591. $hdId = $custom->hdId ?? 0;
  592. $hd = HdClass::getLockById($hdId);
  593. if (empty($hd)) {
  594. util::fail('花店信息缺失,编号5363');
  595. }
  596. $customBalance = bcadd((string)($custom->balance ?? '0'), $amount, 2);
  597. $custom->balance = $customBalance;
  598. $custom->isDebt = bccomp($customBalance, '0', 2) < 0 ? 1 : 0;
  599. $custom->save();
  600. $hdBalance = bcadd((string)($hd->balance ?? '0'), $amount, 2);
  601. $hd->balance = $hdBalance;
  602. if (bccomp($hdBalance, '0', 2) < 0) {
  603. $hd->debt = 2;
  604. }
  605. $hd->save();
  606. if (floatval($customBalance) !== floatval($hdBalance)) {
  607. util::fail('余额错误,请联系管理员,编号' . $hdId);
  608. }
  609. $refundSn = $refund->refundSn ?? '';
  610. $orderId = intval($refund->orderId ?? 0);
  611. $saleOrderSn = !empty($order) ? ($order->orderSn ?? '') : '';
  612. if ($saleOrderSn === '' && $orderId > 0) {
  613. $saleOrderSn = $refund->orderSn ?? '';
  614. }
  615. // 无原单流水只挂售后单号,避免「原单:」空串误导
  616. $event = ($orderId > 0 && $saleOrderSn !== '')
  617. ? "跨天售后返充余额,售后单:{$refundSn},原单:{$saleOrderSn}"
  618. : "无原单退款返充余额,售后单:{$refundSn}";
  619. $capitalType = dict::getDict('capitalType', 'hdRefund', 'id');
  620. $change = [
  621. 'customId' => $custom->id ?? 0,
  622. 'customName' => $custom->name ?? '',
  623. 'relateId' => $refund->id ?? 0,
  624. 'relateSn' => $refundSn,
  625. 'onlinePay' => 1,
  626. 'capitalType' => $capitalType,
  627. 'amount' => $amount,
  628. 'balance' => $customBalance,
  629. 'io' => 1,
  630. 'side' => 0,
  631. 'payWay' => 2,
  632. 'event' => $event,
  633. 'staffId' => $refund->shopAdminId ?? 0,
  634. 'staffName' => $refund->shopAdminName ?? '',
  635. 'shopId' => $refund->shopId ?? 0,
  636. 'mainId' => $refund->mainId ?? 0,
  637. 'refundOrderId' => $orderId,
  638. 'refundOrderSn' => $saleOrderSn,
  639. 'remark' => '',
  640. ];
  641. BalanceChangeClass::add($change, true);
  642. // 返充入账后:优先结当前售后原单挂账,剩余再 FIFO(不再二次扣余额)
  643. $balanceBefore = bcsub($customBalance, $amount, 2);
  644. self::fifoClearAfterRefundCredit($custom, $hd, $refund, $amount, $balanceBefore, $order);
  645. $custom = CustomClass::getById($custom->id ?? 0, true);
  646. return bcadd((string)($custom->balance ?? $customBalance), '0', 2);
  647. }
  648. //欠款和余额支付的售后 ssh 20250803
  649. public static function skRefundDebtAmountReduce($custom, $amount, $refund, $payWay)
  650. {
  651. $hdId = $custom->hdId ?? 0;
  652. $hd = HdClass::getLockById($hdId);
  653. if (empty($hd)) {
  654. util::fail('花店信息缺失,编号5362');
  655. }
  656. // 入账前净余额,供结账单 payWay 判定
  657. $balanceBefore = bcadd((string)($custom->balance ?? '0'), '0', 2);
  658. // 原始支付方式:后面流水会改写成余额付,FIFO 判定要用原值
  659. $originPayWay = intval($payWay);
  660. $customBalance = bcadd($custom->balance, $amount, 2);
  661. $custom->balance = $customBalance;
  662. if ($custom->balance < 0) {
  663. $custom->isDebt = 1;
  664. }
  665. $custom->save();
  666. $hdBalance = bcadd($hd->balance, $amount, 2);
  667. $hd->balance = $hdBalance;
  668. if ($hd->balance < 0) {
  669. $hd->debt = 2;
  670. }
  671. $hd->save();
  672. if (floatval($customBalance) !== floatval($hdBalance)) {
  673. util::fail('余额错误,请联系管理员,编号' . $hdId);
  674. }
  675. $relateId = $refund->id ?? 0;
  676. $customId = $custom->id ?? 0;
  677. $refundSn = $refund->refundSn ?? '';
  678. $orderSn = $refund->orderSn ?? '';
  679. $orderId = $refund->orderId ?? 0;
  680. $order = OrderClass::getLockById($orderId);
  681. if (empty($order)) {
  682. util::fail('没有找到订单哈!');
  683. }
  684. // 多处需要同步修改 balance_pay_give
  685. $mustUseGiveAmount = 0;
  686. $buyAmount = 0;
  687. if ($payWay == 3) {
  688. //如果是欠款单售后,没有退款到赠送余额的情况
  689. $buyAmount = $amount;
  690. } elseif ($payWay == 2) {
  691. //这个是总消费余额中充值余额部分
  692. $payBalance = $order->payBalance ?? 0;
  693. //这个是累计已经退还的余额
  694. $balanceTk = $order->balanceTk ?? 0;
  695. $currentBalanceTk = bcadd($balanceTk, $amount, 2);
  696. //当前累计退还的余额如果超过了充值余额的话,说明要退还赠送的余额了
  697. if ($currentBalanceTk > $payBalance) {
  698. $pastAmount = bcsub($currentBalanceTk, $payBalance, 2);
  699. if ($pastAmount > $amount) {
  700. $mustUseGiveAmount = $amount;
  701. } else {
  702. $buyAmount = bcsub($amount, $pastAmount, 2);
  703. $mustUseGiveAmount = bcsub($amount, $buyAmount, 2);
  704. }
  705. } else {
  706. //累计退还的余额,还没超过充值余额,还是退充值余额部分
  707. $buyAmount = $amount;
  708. }
  709. } else {
  710. util::fail('无效的支付方式!编号69880');
  711. }
  712. $staffId = $refund->shopAdminId ?? 0;
  713. $staffName = $refund->shopAdminName ?? '';
  714. $capitalType = dict::getDict('capitalType', 'hdRefund', 'id');
  715. $event = "订单售后 " . $refundSn;
  716. $customName = $custom->name ?? '';
  717. $onlinePay = 1;
  718. $side = 0;
  719. $payWay = 2;//余额支付
  720. $change = [
  721. 'customId' => $customId,
  722. 'customName' => $customName,
  723. 'relateId' => $relateId,
  724. 'relateSn' => $refundSn,
  725. 'onlinePay' => $onlinePay,
  726. 'capitalType' => $capitalType,
  727. 'amount' => $amount,
  728. 'balance' => $customBalance,
  729. 'io' => 1,
  730. 'side' => $side,
  731. 'payWay' => $payWay,
  732. 'event' => $event,
  733. 'staffId' => $staffId,
  734. 'staffName' => $staffName,
  735. 'shopId' => $refund->shopId,
  736. 'mainId' => $refund->mainId,
  737. 'refundOrderId' => $orderId,
  738. 'refundOrderSn' => $orderSn,
  739. 'remark' => '',
  740. ];
  741. BalanceChangeClass::add($change, true);
  742. $order->balanceTk = bcadd($order->balanceTk, $amount, 2);
  743. if ($order->balanceTk < 0) {
  744. util::fail('不能小于0,编号88672');
  745. }
  746. $order->save();
  747. if ($buyAmount > 0) {
  748. $customBalancePay = bcadd($custom->balancePay, $buyAmount, 2);
  749. $custom->balancePay = $customBalancePay;
  750. $custom->save();
  751. $hdBalancePay = bcadd($hd->balancePay, $buyAmount, 2);
  752. $hd->balancePay = $hdBalancePay;
  753. $hd->save();
  754. $payChange = [
  755. 'customId' => $customId,
  756. 'customName' => $customName,
  757. 'relateId' => $relateId,
  758. 'relateSn' => $refundSn,
  759. 'onlinePay' => $onlinePay,
  760. 'capitalType' => $capitalType,
  761. 'amount' => $buyAmount,
  762. 'balance' => $hdBalancePay,
  763. 'io' => 1,
  764. 'side' => $side,
  765. 'payWay' => $payWay,
  766. 'event' => $event,
  767. 'staffId' => $staffId,
  768. 'staffName' => $staffName,
  769. 'shopId' => $refund->shopId,
  770. 'mainId' => $refund->mainId,
  771. 'refundOrderId' => $orderId,
  772. 'refundOrderSn' => $orderSn,
  773. 'remark' => '',
  774. ];
  775. BalancePayChangeClass::add($payChange, true);
  776. $order->payBalanceTk = bcadd($order->payBalanceTk, $buyAmount, 2);
  777. if ($order->payBalanceTk < 0) {
  778. util::fail('不能小于0,编号88673');
  779. }
  780. $order->save();
  781. }
  782. if ($mustUseGiveAmount > 0) {
  783. $customBalanceGive = bcadd($custom->balanceGive, $mustUseGiveAmount, 2);
  784. $custom->balanceGive = $customBalanceGive;
  785. $custom->save();
  786. $hdBalanceGive = bcadd($hd->balanceGive, $mustUseGiveAmount, 2);
  787. $hd->balanceGive = $hdBalanceGive;
  788. $hd->save();
  789. $giveChange = [
  790. 'customId' => $customId,
  791. 'customName' => $customName,
  792. 'relateId' => $relateId,
  793. 'relateSn' => $refundSn,
  794. 'onlinePay' => $onlinePay,
  795. 'capitalType' => $capitalType,
  796. 'amount' => $mustUseGiveAmount,
  797. 'balance' => $hdBalanceGive,
  798. 'io' => 1,
  799. 'side' => $side,
  800. 'payWay' => $payWay,
  801. 'event' => $event,
  802. 'staffId' => $staffId,
  803. 'staffName' => $staffName,
  804. 'shopId' => $refund->shopId,
  805. 'mainId' => $refund->mainId,
  806. 'refundOrderId' => $orderId,
  807. 'refundOrderSn' => $orderSn,
  808. 'remark' => '',
  809. ];
  810. BalanceGiveChangeClass::add($giveChange, true);
  811. $order->giveBalanceTk = bcadd($order->giveBalanceTk, $mustUseGiveAmount, 2);
  812. if ($order->giveBalanceTk < 0) {
  813. util::fail('不能小于0,编号88675');
  814. }
  815. $order->save();
  816. }
  817. // 当天挂账售后已先减 remainDebtPrice,再 FIFO 优先本单会重复销账;仅隔天/返充类或余额付原路才消欠
  818. $sameDay = intval($refund->sameDay ?? 1);
  819. $debtPay = intval(dict::getDict('payWay', 'debtPay'));
  820. $skipFifo = ($originPayWay === $debtPay && $sameDay === 1);
  821. if (!$skipFifo) {
  822. self::fifoClearAfterRefundCredit($custom, $hd, $refund, $amount, $balanceBefore, $order);
  823. }
  824. }
  825. /**
  826. * 售后返充/原路退余额后销挂账:优先当前售后原单 remainDebtPrice(可部分结),再按 id 升序 FIFO。
  827. * 调用时机:余额已入账;本方法只用本次金额作资金池,不再扣 balance。
  828. *
  829. * @param object $custom 客户(已加锁)
  830. * @param object $hd 花店账户
  831. * @param object $refund 售后单
  832. * @param string|float $amount 本次入账金额
  833. * @param string|float $balanceBefore 入账前净余额
  834. * @param object|null $order 售后关联销售单
  835. */
  836. protected static function fifoClearAfterRefundCredit($custom, $hd, $refund, $amount, $balanceBefore, $order = null)
  837. {
  838. $pool = bcadd((string)$amount, '0', 2);
  839. if (bccomp($pool, '0', 2) <= 0) {
  840. return;
  841. }
  842. $customId = intval($custom->id ?? 0);
  843. if ($customId <= 0) {
  844. return;
  845. }
  846. $preferOrderId = !empty($order) ? intval($order->id ?? 0) : intval($refund->orderId ?? 0);
  847. $plan = self::planFifoClearByPool($customId, $pool, $preferOrderId);
  848. if (empty($plan)) {
  849. return;
  850. }
  851. $shopId = intval($refund->shopId ?? ($custom->shopId ?? 0));
  852. $shop = $shopId > 0 ? ShopClass::getById($shopId, true) : null;
  853. if (empty($shop)) {
  854. // 无门店无法建结账单,跳过销账(余额已入账,不阻断售后)
  855. return;
  856. }
  857. $settleParams = [
  858. 'staffId' => intval($refund->shopAdminId ?? 0),
  859. 'staffName' => (string)($refund->shopAdminName ?? ''),
  860. ];
  861. $set = SettleClass::addSettle($plan, $shop, $custom, $hd, $settleParams);
  862. if (!empty($set)) {
  863. SettleClass::clearSettle($set);
  864. }
  865. // 刷新客户欠款标记(有未结挂账单则为欠款户)
  866. $leftDebt = OrderClass::getAllByCondition(['customId' => $customId, 'debt' => 1], null, 'id', null, true);
  867. $customFresh = self::getLockById($customId);
  868. if (!empty($customFresh)) {
  869. $customFresh->isDebt = !empty($leftDebt) ? 1 : 0;
  870. $customFresh->save(false, ['isDebt']);
  871. }
  872. }
  873. /**
  874. * 销挂账分配:可选优先本单,剩余按订单 id 升序 FIFO。
  875. * prefer 路径只用 remainDebtPrice,不用 actPrice 兜底,避免脏数据多销。
  876. *
  877. * @param int $customId
  878. * @param string|float $poolAmount
  879. * @param int $preferOrderId
  880. * @return array<int, array{orderId:int, clearAmount:string, orderSn:string}>
  881. */
  882. protected static function planFifoClearByPool($customId, $poolAmount, $preferOrderId = 0)
  883. {
  884. $pool = bcadd((string)$poolAmount, '0', 2);
  885. if (bccomp($pool, '0', 2) <= 0) {
  886. return [];
  887. }
  888. $orderList = OrderClass::getAllByCondition(['customId' => $customId, 'debt' => 1], 'id asc', '*', null, true);
  889. if (empty($orderList)) {
  890. return [];
  891. }
  892. $plan = [];
  893. $used = '0.00';
  894. $preferOrderId = intval($preferOrderId);
  895. // 1)售后原单仍挂账:先结本单(不够则部分结)
  896. if ($preferOrderId > 0) {
  897. foreach ($orderList as $ord) {
  898. if (intval($ord->id ?? 0) !== $preferOrderId) {
  899. continue;
  900. }
  901. $remain = bcadd((string)($ord->remainDebtPrice ?? '0'), '0', 2);
  902. if (bccomp($remain, '0', 2) <= 0) {
  903. break;
  904. }
  905. $clearAmount = bccomp($remain, $pool, 2) <= 0 ? $remain : $pool;
  906. $plan[] = [
  907. 'orderId' => $preferOrderId,
  908. 'clearAmount' => $clearAmount,
  909. 'orderSn' => $ord->orderSn ?? '',
  910. ];
  911. $used = bcadd($used, $clearAmount, 2);
  912. break;
  913. }
  914. }
  915. // 2)剩余金额 FIFO(跳过已优先处理的本单)
  916. foreach ($orderList as $ord) {
  917. $left = bcsub($pool, $used, 2);
  918. if (bccomp($left, '0', 2) <= 0) {
  919. break;
  920. }
  921. $oid = intval($ord->id ?? 0);
  922. if ($preferOrderId > 0 && $oid === $preferOrderId) {
  923. continue;
  924. }
  925. $remain = bcadd((string)($ord->remainDebtPrice ?? '0'), '0', 2);
  926. if (bccomp($remain, '0', 2) <= 0) {
  927. continue;
  928. }
  929. $clearAmount = bccomp($remain, $left, 2) <= 0 ? $remain : $left;
  930. $plan[] = [
  931. 'orderId' => $oid,
  932. 'clearAmount' => $clearAmount,
  933. 'orderSn' => $ord->orderSn ?? '',
  934. ];
  935. $used = bcadd($used, $clearAmount, 2);
  936. }
  937. return $plan;
  938. }
  939. //添加客户 ssh 2021.2.28
  940. public static function addCustom($data)
  941. {
  942. return self::add($data, true);
  943. }
  944. //创建或获取客户信息 ssh 2021.3.19
  945. /**
  946. * 建立用户与花店的 xhCustom / hd 关系(花店增加客户)
  947. * @param object $shop 门店
  948. * @param object $user 商城用户
  949. * @param int $inviterCustomId 分享邀请人 xhCustom.id,仅新建客户时尝试拉新绑定
  950. * @return array|false custom、hd、isNewCustom、inviteBound
  951. */
  952. public static function buildRelation($shop, $user, $inviterCustomId = 0)
  953. {
  954. if (empty($user)) {
  955. return false;
  956. }
  957. if (empty($shop)) {
  958. return false;
  959. }
  960. if ($shop->ptStyle == 2) {
  961. util::fail('有问题,批发店状态');
  962. }
  963. $salt = stringUtil::charsShuffleLowerCase(8);
  964. $isNewCustom = 0;
  965. /** 仅 xhCustom 新建时为 1,供分享拉新绑定(与 hd 新建触发的 $isNewCustom 区分) */
  966. $customCreated = 0;
  967. $userId = $user->id;
  968. $name = $user->name ?? '';
  969. $mobile = $user->mobile ?? '';
  970. $shopId = $shop->id ?? 0;
  971. $mainId = $shop->mainId ?? 0;
  972. $hdAvatar = $shop->avatar ?? '';
  973. $sjId = $shop->sjId ?? 0;
  974. $sjName = $shop->merchantName ?? '';
  975. $shopName = $shop->shopName ?? '';
  976. $hdMobile = $shop->mobile ?? '';
  977. $hdName = $shopName == '首店' ? $sjName : $sjName . ' ' . $shopName;
  978. $hdPy = stringUtil::py($hdName);
  979. $custom = self::getByCondition(['shopId' => $shopId, 'userId' => $userId], true);
  980. if (empty($custom)) {
  981. $py = stringUtil::py($name);
  982. $visitTime = date("Y-m-d H:i:s");
  983. $data = [
  984. 'userId' => $userId,
  985. 'sjId' => $sjId,
  986. 'shopId' => $shopId,
  987. 'mainId'=>$mainId,
  988. 'name' => $name,
  989. 'originName' => $name,
  990. 'py' => $py,
  991. 'mobile' => $mobile,
  992. 'visitTime' => $visitTime,
  993. 'salt' => $salt,
  994. ];
  995. $birthdaySet = $user->birthdaySet ?? 0;
  996. if ($birthdaySet == 1) {
  997. //如果用户自己设置过了生日,则生日给传过去
  998. $lunar = $user->lunar ?? 0;
  999. $birthday = $user->birthday ?? '';
  1000. $birthdayTime = $user->birthdayTime ?? 0;
  1001. $birthdayMonth = $user->birthdayMonth ?? 0;
  1002. $birthdayDate = $user->birthdayDate ?? 0;
  1003. //如果当年的生日时间没有更新,则需要给更新
  1004. $year = date("Y", strtotime($birthday));
  1005. $thisYear = date("Y");
  1006. if ($year != $thisYear) {
  1007. if ($lunar == 1) {
  1008. try {
  1009. //农历转阳历,有多处使用,需要同步修改,关键词change_my_birthday
  1010. $calendar = new Calendar();
  1011. $result = $calendar->lunar(date("Y"), $birthdayMonth, $birthdayDate);
  1012. $month = $result['gregorian_month'] ?? 1;
  1013. $date = $result['gregorian_day'] ?? 1;
  1014. $birthday = date("Y") . '-' . $month . '-' . $date;
  1015. $user->birthday = $birthday;
  1016. $user->save();
  1017. CustomClass::updateByCondition(['userId' => $userId], ['birthday' => $birthday]);
  1018. } catch (\InvalidArgumentException $e) {
  1019. $msg = $e->getMessage();
  1020. noticeUtil::push("同步生日出错了,需要检查确认,userId:" . $userId . ' 月份:' . $birthdayMonth . ' 日期:' . $birthdayDate . ' ' . $msg, '15280215347');
  1021. $birthday = '0000-00-00 00:00:00';
  1022. }
  1023. } else {
  1024. $birthday = date("Y") . '-' . $birthdayMonth . '-' . $birthdayDate;
  1025. $user->birthday = $birthday;
  1026. $user->save();
  1027. CustomClass::updateByCondition(['userId' => $userId], ['birthday' => $birthday]);
  1028. }
  1029. }
  1030. $data['birthday'] = $birthday;
  1031. $data['birthdayTime'] = $birthdayTime;
  1032. $data['birthdayMonth'] = $birthdayMonth;
  1033. $data['birthdayDate'] = $birthdayDate;
  1034. $data['lunar'] = $lunar;
  1035. }
  1036. // 处理并发插入:尝试插入,如果遇到唯一键冲突则重新查询
  1037. try {
  1038. $custom = self::addCustom($data);
  1039. $isNewCustom = 1;
  1040. $customCreated = 1;
  1041. } catch (\yii\db\IntegrityException $e) {
  1042. // 唯一键冲突,说明其他并发请求已经插入,重新查询
  1043. if (strpos($e->getMessage(), 'Duplicate entry') !== false) {
  1044. $custom = self::getByCondition(['shopId' => $shopId, 'userId' => $userId], true);
  1045. if (empty($custom)) {
  1046. // 如果仍然查不到,则抛出异常
  1047. throw $e;
  1048. }
  1049. $isNewCustom = 0;
  1050. $customCreated = 0;
  1051. } else {
  1052. throw $e;
  1053. }
  1054. }
  1055. }
  1056. $customId = $custom->id ?? 0;
  1057. $hd = HdClass::getByCondition(['shopId' => $shopId, 'userId' => $userId], true);
  1058. if (empty($hd)) {
  1059. $hdData = [
  1060. 'shopId' => $shopId,
  1061. 'userId' => $userId,
  1062. 'name' => $hdName,
  1063. 'sjId' => $sjId,
  1064. 'mainId' => $mainId,
  1065. 'customId' => $customId,
  1066. 'avatar' => $hdAvatar,
  1067. 'py' => $hdPy,
  1068. 'mobile' => $hdMobile,
  1069. 'province' => $shop->province ?? '',
  1070. 'city' => $shop->city ?? '',
  1071. 'dist' => $shop->dist ?? '',
  1072. 'address' => $shop->address ?? '',
  1073. 'floor' => $shop->floor ?? '',
  1074. 'fullAddress' => $shop->fullAddress ?? '',
  1075. 'showAddress' => $shop->showAddress ?? '',
  1076. 'lat' => $shop->lat ?? '',
  1077. 'long' => $shop->long ?? '',
  1078. 'salt' => $salt,
  1079. ];
  1080. // 处理并发插入:尝试插入,如果遇到唯一键冲突则重新查询
  1081. try {
  1082. $hd = HdClass::addData($hdData);
  1083. } catch (\yii\db\IntegrityException $e) {
  1084. // 唯一键冲突,说明其他并发请求已经插入,重新查询
  1085. if (strpos($e->getMessage(), 'Duplicate entry') !== false) {
  1086. $hd = HdClass::getByCondition(['shopId' => $shopId, 'userId' => $userId], true);
  1087. if (empty($hd)) {
  1088. // 如果仍然查不到,则抛出异常
  1089. throw $e;
  1090. }
  1091. } else {
  1092. throw $e;
  1093. }
  1094. }
  1095. $isNewCustom = 1;
  1096. }
  1097. $hdId = $hd->id ?? 0;
  1098. $custom->hdId = $hdId;
  1099. $custom->save();
  1100. // 新建 xhCustom 时:customId 无分销记录则创建,有邀请人则绑定
  1101. $inviteBound = 0;
  1102. $inviterCustomId = (int)$inviterCustomId;
  1103. try {
  1104. $inviteBound = DistributionUserClass::bindInviteOnRegister(
  1105. (int)$shopId,
  1106. (int)$customId,
  1107. $inviterCustomId
  1108. );
  1109. } catch (\Throwable $e) {
  1110. // 分销初始化失败不影响建客主流程
  1111. }
  1112. if ($isNewCustom == 1) {
  1113. WxMessageClass::newHdCustomInform($shop, $custom);
  1114. }
  1115. // 新客/受邀新客红包:仅新建 xhCustom 时触发;受邀优先且不叠加发新客红包
  1116. if ($customCreated == 1) {
  1117. try {
  1118. $mainId = (int)($shop->mainId ?? 0);
  1119. $customArr = is_object($custom) ? $custom->attributes : $custom;
  1120. if ($inviteBound == 1) {
  1121. HbAutoRuleClass::tryIssueOnRegister($shopId, $mainId, $customArr, HbAutoRule::TYPE_INVITED);
  1122. } else {
  1123. HbAutoRuleClass::tryIssueOnRegister($shopId, $mainId, $customArr, HbAutoRule::TYPE_NEW);
  1124. }
  1125. } catch (\Throwable $e) {
  1126. Yii::error('注册自动发红包失败 customId=' . $customId . ' ' . $e->getMessage(), __METHOD__);
  1127. }
  1128. }
  1129. return [
  1130. 'custom' => $custom,
  1131. 'hd' => $hd,
  1132. 'isNewCustom' => $customCreated,
  1133. 'inviteBound' => $inviteBound,
  1134. ];
  1135. }
  1136. //获取客户信息
  1137. public static function getCustom($data)
  1138. {
  1139. $custom = self::getByCondition($data);
  1140. if (empty($custom)) {
  1141. $custom = self::add($data);
  1142. }
  1143. return $custom;
  1144. }
  1145. //获取客户信息 ssh 2021.2.1
  1146. public static function getCustomInfo($id)
  1147. {
  1148. $custom = self::getById($id);
  1149. if (empty($custom)) {
  1150. return $custom;
  1151. }
  1152. $list = self::groupBaseInfo([$custom]);
  1153. return current($list);
  1154. }
  1155. //获取客户信息 ssh 2021.3.19
  1156. public static function getCustomByIds($ids)
  1157. {
  1158. $list = self::getByIds($ids);
  1159. $list = self::groupBaseInfo($list);
  1160. return $list;
  1161. }
  1162. public static function valid($info, $shopId)
  1163. {
  1164. if (isset($info['shopId']) && $info['shopId'] == $shopId) {
  1165. return true;
  1166. }
  1167. util::fail('客户信息无效');
  1168. }
  1169. //整合基本信息 ssh 2021.1.31
  1170. public static function groupBaseInfo($list)
  1171. {
  1172. if (empty($list)) {
  1173. return $list;
  1174. }
  1175. foreach ($list as $key => $val) {
  1176. $shortAvatar = $val['avatar'] ?? '';
  1177. $avatar = imgUtil::groupImg($shortAvatar) . "?x-oss-process=image/resize,m_fill,h_800,w_800";
  1178. $smallAvatar = imgUtil::groupImg($shortAvatar) . "?x-oss-process=image/resize,m_fill,h_130,w_130";
  1179. $bigAvatar = imgUtil::groupImg($shortAvatar) . "?x-oss-process=image/resize,m_fill,h_700,w_700";
  1180. $list[$key]['shortAvatar'] = $shortAvatar;
  1181. $list[$key]['avatar'] = $avatar;
  1182. $list[$key]['smallAvatar'] = $smallAvatar;
  1183. $list[$key]['bigAvatar'] = $bigAvatar;
  1184. //超时未下单
  1185. $recentExpend = $val['recentExpend'] ?? '';
  1186. $list[$key]['overTimeUnExpend'] = 0;
  1187. if ($recentExpend == '0000-00-00 00:00:00') {
  1188. $list[$key]['overTimeUnExpend'] = 10000;
  1189. } else {
  1190. $recentExpendTime = strtotime($recentExpend);
  1191. $seven = bcmul(86400, 7);
  1192. $sevenTime = bcadd($recentExpendTime, $seven);
  1193. if ($sevenTime < time()) {
  1194. $list[$key]['overTimeUnExpend'] = 7;
  1195. }
  1196. $month = bcmul(86400, 30);
  1197. $monthTime = bcadd($recentExpendTime, $month);
  1198. if ($monthTime < time()) {
  1199. $list[$key]['overTimeUnExpend'] = 30;
  1200. }
  1201. $halfYear = bcmul(86400, 180);
  1202. $halfYearTime = bcadd($recentExpendTime, $halfYear);
  1203. if ($halfYearTime < time()) {
  1204. $list[$key]['overTimeUnExpend'] = 180;
  1205. }
  1206. $year = bcmul(86400, 365);
  1207. $yearTime = bcmul($recentExpendTime, $year);
  1208. if ($yearTime < time()) {
  1209. $list[$key]['overTimeUnExpend'] = 365;
  1210. }
  1211. }
  1212. }
  1213. return $list;
  1214. }
  1215. // 客户消费等级批量变更
  1216. public static function updateCustomExpenseLevel($data)
  1217. {
  1218. $shopId = $data['shopId'];
  1219. $mainId = $data['mainId'];
  1220. $customs = self::getAllByCondition(['shopId' => $shopId], null, 'id, name, hdId, userId, buyAmount, growth, member, memberName, discount', null, true);
  1221. $levelDatas = MemberLevelClass::getAllByCondition(['mainId' => $mainId], 'amount DESC', 'id, name, level, amount, discount');
  1222. if (!empty($customs) && !empty($levelDatas)) {
  1223. foreach ($customs as $c) {
  1224. // $buyAmount = 0;
  1225. // // 获取所有零售订单,计算消费金额
  1226. // $orderList = \bizHd\order\classes\OrderClass::getAllByCondition(['customId' => $c->id], null, 'id, actPrice');
  1227. // if (!empty($orderList)) {
  1228. // foreach ($orderList as $order) {
  1229. // $buyAmount = bcadd($buyAmount, $order['actPrice'], 2);
  1230. // }
  1231. // }
  1232. // $c->buyAmount = $buyAmount;
  1233. // 根据 growth 设置等级
  1234. $memberData = self::getCustomExpenseLevel($c->growth, $mainId, $levelDatas); // 设置等级多处需要同步修改的,请搜索:getCustomExpenseLevel
  1235. if ($c->member != $memberData['level'] || $c->memberName != $memberData['name']) {
  1236. $hdId = $c->hdId;
  1237. $hd = HdClass::getById($hdId, true);
  1238. $change = [
  1239. 'customId' => $c->id,
  1240. 'customName' => $c->name,
  1241. 'hdId' => $hd->id,
  1242. 'hdName' => $hd->name,
  1243. 'mainId' => $mainId,
  1244. 'shopId' => $shopId,
  1245. 'targetId' => 0,
  1246. 'rechargeAmount' => 0,
  1247. 'days' => 0,
  1248. 'daysBefore' => '0000-00-00 00:00:00',
  1249. 'daysAfter' => '0000-00-00 00:00:00',
  1250. 'beforeLevel' => $c->member,
  1251. 'afterLevel' => $memberData['level'],
  1252. 'beforeName' => $c->memberName,
  1253. 'afterName' => $memberData['name'],
  1254. 'style' => 1, //手动修改会员,脚本执行
  1255. 'event' => '系统脚本修改',
  1256. 'staffId' => 0,
  1257. 'staffName' => '',
  1258. ];
  1259. MemberChangeClass::add($change);
  1260. }
  1261. $c->member = $memberData['level'];
  1262. $c->memberName = $memberData['name'];
  1263. $c->discount = bcdiv(floatval($memberData['discount']), 10, 2);
  1264. $c->save();
  1265. if (!empty($c->hdId)) {
  1266. $hd = HdClass::getById($c->hdId, true);
  1267. if (!empty($hd)) {
  1268. $hd->member = $memberData['level'];
  1269. $hd->memberName = $memberData['name'];
  1270. $hd->discount = $c->discount;
  1271. $hd->save();
  1272. }
  1273. }
  1274. // 更新客户所对应花店的消费金额
  1275. // HdClass::updateByCondition(['shopId'=>$shopId, 'userId'=>$c->userId], ['expendAmount'=>$buyAmount]);
  1276. }
  1277. }
  1278. return true;
  1279. }
  1280. // 获取客户消费等级
  1281. public static function getCustomExpenseLevel($growth, $mainId, $levelDatas=[])
  1282. {
  1283. if (empty($levelDatas)) {
  1284. $levelDatas = MemberLevelClass::getAllByCondition(['mainId' => $mainId], 'amount DESC', 'id, name, level, amount, discount');
  1285. }
  1286. foreach ($levelDatas as $data) {
  1287. if ($growth >= $data['amount']) {
  1288. return $data;
  1289. }
  1290. }
  1291. return ['level'=>0, 'name'=>'', 'discount'=>10];
  1292. }
  1293. }