GhsPurchaseBalanceMergeController.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. <?php
  2. namespace console\controllers;
  3. use biz\ghs\classes\GhsClass as BizGhsClass;
  4. use bizGhs\custom\classes\AccountMoneyClass;
  5. use common\components\dict;
  6. use yii\console\Controller;
  7. /**
  8. * ghsApp 采购供货商 xhGhs 余额合并(按采购待结订单重算)
  9. *
  10. * 【用途】仅处理 ghsApp 采购供货商行(ownPtStyle=ghs/kmGhs),不处理 hd 花店侧 xhGhs 行(ownPtStyle=hd)。
  11. * 【公式】净 balance = max(当前正余额,0) - 待结 ghs 采购单 actPrice 合计;debtNum 与有效待结单数对齐。
  12. * 【可重复执行】默认 force=1,已 balanceMerged 的行也会重算,并清理 actPrice<=0/已取消仍标待结的幽灵单。
  13. *
  14. * hd 花店侧供货商请用:php yii balance-merge/run
  15. *
  16. * 用法:php yii ghs-purchase-balance-merge/run
  17. * 预览:php yii ghs-purchase-balance-merge/run --dryRun=1
  18. * 单户:php yii ghs-purchase-balance-merge/run --ghsId=123
  19. * 仅未合并:php yii ghs-purchase-balance-merge/run --force=0
  20. */
  21. class GhsPurchaseBalanceMergeController extends Controller
  22. {
  23. /** 1=只预览不写库 */
  24. public $dryRun = 0;
  25. /** 指定 xhGhs.id,0=扫全表符合条件的 ghsApp 采购供货商行 */
  26. public $ghsId = 0;
  27. /** 1=已合并行也重算(默认);0=仅处理未合并行 */
  28. public $force = 1;
  29. public function options($actionID)
  30. {
  31. return array_merge(parent::options($actionID), ['dryRun', 'ghsId', 'force']);
  32. }
  33. /**
  34. * 执行或预览:仅 ghsApp 采购供货商(ownPtStyle=ghs/kmGhs)按采购待结订单重算净余额。
  35. */
  36. public function actionRun()
  37. {
  38. $dry = (int)$this->dryRun === 1;
  39. $force = (int)$this->force === 1;
  40. $ghsId = intval($this->ghsId);
  41. echo $dry ? "【预览:ghsApp 采购供货商按订单重算余额】\n" : "【执行:ghsApp 采购供货商按订单重算余额】\n";
  42. echo 'force=' . ($force ? '1(含已合并)' : '0(仅未合并)') . PHP_EOL;
  43. if ($ghsId > 0) {
  44. $count = $this->mergeOneGhs($ghsId, $dry, $force) ? 1 : 0;
  45. echo "完成:处理 {$count} 条,dryRun=" . ($dry ? '1' : '0') . PHP_EOL;
  46. return;
  47. }
  48. $count = 0;
  49. $purchasePtStyles = $this->getGhsAppPurchasePtStyles();
  50. $where = [
  51. 'ownShopId>' => 0,
  52. 'ownPtStyle' => ['in', $purchasePtStyles],
  53. ];
  54. if (!$force && $this->columnExists('xhGhs', 'balanceMerged')) {
  55. $where['balanceMerged'] = 0;
  56. } elseif (!$force) {
  57. $where['debtAmount>'] = 0;
  58. }
  59. $list = BizGhsClass::getAllByCondition($where, null, 'id,ownShopId,ownPtStyle,balance,debtAmount,debtNum,balanceMerged', null, true);
  60. foreach ($list as $ghs) {
  61. if ($this->mergeOneGhs(intval($ghs->id ?? 0), $dry, $force)) {
  62. $count++;
  63. }
  64. }
  65. // ownPtStyle 未回填的历史行
  66. $legacyWhere = [
  67. 'ownShopId>' => 0,
  68. 'ownPtStyle' => 0,
  69. ];
  70. if (!$force && $this->columnExists('xhGhs', 'balanceMerged')) {
  71. $legacyWhere['balanceMerged'] = 0;
  72. }
  73. $legacyList = BizGhsClass::getAllByCondition($legacyWhere, null, 'id,ownShopId,ownPtStyle,balance,debtAmount,debtNum,balanceMerged', null, true);
  74. foreach ($legacyList as $ghs) {
  75. if ($this->mergeOneGhs(intval($ghs->id ?? 0), $dry, $force)) {
  76. $count++;
  77. }
  78. }
  79. echo "完成:处理 {$count} 条,dryRun=" . ($dry ? '1' : '0') . PHP_EOL;
  80. }
  81. /**
  82. * ghsApp 采购买方平台类型:二级批发(2)、基地端(4);不含 hd 花店(1)。
  83. */
  84. protected function getGhsAppPurchasePtStyles()
  85. {
  86. return [
  87. (int)dict::getDict('ptStyle', 'ghs'),
  88. (int)dict::getDict('ptStyle', 'kmGhs'),
  89. ];
  90. }
  91. /**
  92. * 合并单行;预览模式只打印将写入的金额。
  93. */
  94. protected function mergeOneGhs($ghsId, $dry, $force)
  95. {
  96. if ($ghsId <= 0) {
  97. return false;
  98. }
  99. $ghs = BizGhsClass::getById($ghsId, true);
  100. if (empty($ghs)) {
  101. echo "[跳过] id={$ghsId} 不存在" . PHP_EOL;
  102. return false;
  103. }
  104. if (!AccountMoneyClass::isGhsAppPurchaseSupplierRow($ghs)) {
  105. $ownPtStyle = intval($ghs->ownPtStyle ?? 0);
  106. echo "[跳过] id={$ghsId} 非 ghsApp 采购供货商行(ownPtStyle={$ownPtStyle},hd 行请用 balance-merge)" . PHP_EOL;
  107. return false;
  108. }
  109. $ownShopId = intval($ghs->ownShopId ?? 0);
  110. $oldBalance = bcadd((string)($ghs->balance ?? '0'), '0', 2);
  111. $oldDebtNum = intval($ghs->debtNum ?? 0);
  112. $fixedOrders = AccountMoneyClass::countInvalidPurchaseDebtOrders($ghsId);
  113. $debtStats = AccountMoneyClass::getValidPurchaseDebtStats($ghsId);
  114. $orderDebt = $debtStats['amount'];
  115. $orderDebtNum = $debtStats['num'];
  116. $positiveCredit = bccomp($oldBalance, '0', 2) > 0 ? $oldBalance : '0.00';
  117. $newBalance = bcsub($positiveCredit, $orderDebt, 2);
  118. if ($dry) {
  119. echo "[ghsApp采购供货商] id={$ghsId} ownShopId={$ownShopId} ownPtStyle={$ghs->ownPtStyle}"
  120. . " 原balance={$oldBalance} 原debtNum={$oldDebtNum}"
  121. . " 清理幽灵单={$fixedOrders}"
  122. . " 待结{$orderDebtNum}笔合计={$orderDebt} => 新balance={$newBalance} 新debtNum={$orderDebtNum}" . PHP_EOL;
  123. return true;
  124. }
  125. $locked = BizGhsClass::getLockById($ghsId);
  126. $fixedOrders = AccountMoneyClass::syncInvalidPurchaseDebtOrders($ghsId);
  127. AccountMoneyClass::mergeOwnShopGhsBalanceFromPurchaseOrdersIfNeeded($locked, false, $force);
  128. echo "[已重算] id={$ghsId} 清理幽灵单={$fixedOrders} 待结{$orderDebtNum}笔合计={$orderDebt}"
  129. . " balance {$oldBalance}=>{$newBalance} debtNum {$oldDebtNum}=>{$orderDebtNum}" . PHP_EOL;
  130. return true;
  131. }
  132. /**
  133. * 判断 xhGhs 是否已有 balanceMerged 字段。
  134. */
  135. protected function columnExists($table, $column)
  136. {
  137. $db = \Yii::$app->db;
  138. $schema = $db->getTableSchema($table, true);
  139. return $schema && isset($schema->columns[$column]);
  140. }
  141. }