| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341 |
- <?php
- namespace bizGhs\custom\classes;
- use biz\ghs\classes\GhsClass as BizGhsClass;
- use bizGhs\ghs\classes\GhsBalanceChangeClass;
- use bizGhs\order\classes\PurchaseOrderClass;
- use common\components\dict;
- use Yii;
- /**
- * 【用途】客户/供货商账户金额核心处理类(表 xhGhsCustom、xhGhs)
- * 【为什么】在全部升级到新版、全部账户已合并的前提下,彻底移除旧版 appVersion < 3 兼容逻辑与 balanceMerged 复杂校验,极大地简化计算路径,提升系统性能与稳定性。
- * 【说明】
- * - 数据库中的 balance 已经是唯一的净余额(正数代表有充值余额,负数代表待结欠款)。
- * - 数据库中的 debtAmount 字段已废弃,其值始终为 0.00。
- * - 写业务前调用 ensureCustomMoneyReady / ensureGhsMoneyReady(仅行锁,不触发合并)。
- */
- class AccountMoneyClass
- {
- /**
- * 新端协议版本号:只返回净 balance,不再拆分待结/余额两列。
- */
- const APP_VERSION_NET_BALANCE = 3;
- /**
- * 【用途】获取当前 HTTP 请求里的客户端版本号。
- * 【说明】由于全部已升级到新版,此方法固定返回 3。
- */
- public static function getClientAppVersion()
- {
- return self::APP_VERSION_NET_BALANCE;
- }
- /**
- * 【用途】判断数据行是否带有 balanceMerged 字段。
- * 【说明】已全部合并,此方法固定返回 true。
- */
- public static function hasMergeFlagField($row)
- {
- return true;
- }
- /**
- * 【用途】判断该客户/供货商账户是否已经完成「挂账并入余额」。
- * 【说明】已全部合并,此方法固定返回 true。
- */
- public static function isMerged($row)
- {
- return true;
- }
- /**
- * 【用途】内部取 debtAmount 原始值。
- * 【说明】已全部合并,此方法固定返回 '0.00'。
- */
- protected static function rawDebtAmount($row)
- {
- return '0.00';
- }
- /**
- * 【用途】根据库里的 balance 计算「净账户余额」。
- * 【说明】已全部合并,净额就是 balance。
- */
- public static function calcNetBalance($balance, $debtAmount, $merged = true)
- {
- return bcadd((string)($balance ?? '0.00'), '0', 2);
- }
- /**
- * 【用途】从记录中取出净账户余额。
- * 【说明】已全部合并,直接返回 balance。
- */
- public static function getNetBalanceFromRow($row)
- {
- if (is_array($row)) {
- return bcadd((string)($row['balance'] ?? '0.00'), '0', 2);
- }
- return bcadd((string)($row->balance ?? '0.00'), '0', 2);
- }
- /**
- * 【用途】得到当前账户「待结欠款」数额(正数)。
- * 【规则】净余额 >= 0 时返回 0.00;净余额 < 0 时返回 |净余额|。
- */
- public static function getOutstandingDebt($row)
- {
- $net = self::getNetBalanceFromRow($row);
- if (bccomp($net, '0', 2) >= 0) {
- return '0.00';
- }
- return bcmul($net, '-1', 2);
- }
- /**
- * 【用途】把接口返回给前端的金额字段,按新版形态格式化。
- * 【说明】由于已全部升级至新版,直接返回净 balance。为了前端各页面和打印机安全兼容,
- * 我们将真实的待结欠款(正数)同时赋予 debtAmount 和 remainDebtAmount。
- */
- public static function formatMoneyForClient(array $row, $appVersion = null)
- {
- $net = self::getNetBalanceFromRow($row);
- $row['displayBalance'] = $net;
- $row['balance'] = $net;
-
- // 计算出真实的待结欠款(正数)
- $outstanding = bccomp($net, '0', 2) < 0 ? bcmul($net, '-1', 2) : '0.00';
-
- $row['debtAmount'] = $outstanding;
- $row['remainDebtAmount'] = $outstanding;
- return $row;
- }
- /**
- * 【用途】对 xhGhsCustom(客户)执行一次性「挂账并入余额」。
- * 【说明】已全部合并,此方法直接返回。
- */
- public static function mergeCustomDebtIntoBalanceIfNeeded($custom, $writeBalanceChange = true)
- {
- return $custom;
- }
- /**
- * 【用途】对 xhGhs 执行一次性「挂账并入余额」。
- * 【说明】已全部合并,此方法直接返回。
- */
- public static function mergeGhsDebtIntoBalanceIfNeeded($ghs, $writeBalanceChange = true)
- {
- return $ghs;
- }
- /**
- * 【用途】客户侧金额写操作前置:仅对客户行加锁,不执行挂账并入余额。
- * 【为什么】在全部升级并合并后,写操作只需要锁行即可。
- */
- public static function ensureCustomMoneyReady($custom, $writeMergeChange = true)
- {
- if (empty($custom)) {
- return $custom;
- }
- $customId = is_array($custom) ? ($custom['id'] ?? 0) : ($custom->id ?? 0);
- return CustomClass::getLockById($customId);
- }
- /**
- * 【用途】控制台批量合并。
- * 【说明】已全部合并,此方法直接返回。
- */
- public static function mergeCustomMoneyForScript($custom, $writeMergeChange = true)
- {
- return $custom;
- }
- /**
- * 【用途】判断 xhGhs 是否为 ghsApp「采购供货商」行。
- */
- public static function isGhsAppPurchaseSupplierRow($ghs)
- {
- $ownShopId = intval(is_array($ghs) ? ($ghs['ownShopId'] ?? 0) : ($ghs->ownShopId ?? 0));
- if ($ownShopId <= 0) {
- return false;
- }
- $ownPtStyle = intval(is_array($ghs) ? ($ghs['ownPtStyle'] ?? 0) : ($ghs->ownPtStyle ?? 0));
- if ($ownPtStyle <= 0) {
- $shop = \biz\shop\classes\ShopClass::getById($ownShopId);
- if (!empty($shop)) {
- $ownPtStyle = intval(is_array($shop) ? ($shop['ptStyle'] ?? 0) : ($shop->ptStyle ?? 0));
- }
- }
- $hdPt = (int)dict::getDict('ptStyle', 'hd');
- if ($ownPtStyle === $hdPt) {
- return false;
- }
- $ghsPt = (int)dict::getDict('ptStyle', 'ghs');
- $kmGhsPt = (int)dict::getDict('ptStyle', 'kmGhs');
- return in_array($ownPtStyle, [$ghsPt, $kmGhsPt], true);
- }
- /**
- * 【用途】供货商关系行写操作前置:仅加行锁,不执行挂账并入余额。
- */
- public static function ensureGhsMoneyReady($ghs, $writeMergeChange = true)
- {
- if (empty($ghs)) {
- return $ghs;
- }
- $ghsId = is_array($ghs) ? ($ghs['id'] ?? 0) : ($ghs->id ?? 0);
- return BizGhsClass::getLockById($ghsId);
- }
- /**
- * 【用途】控制台批量合并。
- * 【说明】已全部合并,此方法直接返回。
- */
- public static function mergeGhsMoneyForScript($ghs, $writeMergeChange = true)
- {
- return $ghs;
- }
- /**
- * 【用途】汇总某采购供货商下仍待结的 ghs 采购单金额。
- */
- public static function sumPurchaseOrderDebtForGhs($ghsId)
- {
- $ghsId = intval($ghsId);
- if ($ghsId <= 0) {
- return '0.00';
- }
- $sum = PurchaseOrderClass::sum(
- ['ghsId' => $ghsId, 'debt' => PurchaseOrderClass::DEBT_YES],
- 'actPrice'
- );
- return bcadd((string)($sum ?: '0'), '0', 2);
- }
- /**
- * 【用途】统计某采购供货商仍待结的 ghs 采购单笔数。
- */
- public static function countPurchaseOrderDebtForGhs($ghsId)
- {
- $ghsId = intval($ghsId);
- if ($ghsId <= 0) {
- return 0;
- }
- return (int)PurchaseOrderClass::getCount([
- 'ghsId' => $ghsId,
- 'debt' => PurchaseOrderClass::DEBT_YES,
- ]);
- }
- /**
- * 【用途】统计应清理的幽灵待结单数量。
- */
- public static function countInvalidPurchaseDebtOrders($ghsId)
- {
- $ids = self::collectInvalidPurchaseDebtOrderIds($ghsId);
- return count($ids);
- }
- /**
- * 【用途】有效待结采购单统计。
- * @return array{num:int,amount:string}
- */
- public static function getValidPurchaseDebtStats($ghsId)
- {
- $ghsId = intval($ghsId);
- if ($ghsId <= 0) {
- return ['num' => 0, 'amount' => '0.00'];
- }
- $invalidIds = self::collectInvalidPurchaseDebtOrderIds($ghsId);
- $list = PurchaseOrderClass::getAllByCondition([
- 'ghsId' => $ghsId,
- 'debt' => PurchaseOrderClass::DEBT_YES,
- ], null, 'id,actPrice', null, true);
- $num = 0;
- $amount = '0.00';
- if (!empty($list)) {
- foreach ($list as $order) {
- $orderId = intval($order->id ?? 0);
- if (isset($invalidIds[$orderId])) {
- continue;
- }
- $num++;
- $amount = bcadd($amount, bcadd((string)($order->actPrice ?? '0'), '0', 2), 2);
- }
- }
- return ['num' => $num, 'amount' => $amount];
- }
- /**
- * 【用途】收集幽灵待结采购单 id。
- */
- protected static function collectInvalidPurchaseDebtOrderIds($ghsId)
- {
- $ghsId = intval($ghsId);
- $ids = [];
- if ($ghsId <= 0) {
- return $ids;
- }
- $zeroList = PurchaseOrderClass::getAllByCondition([
- 'ghsId' => $ghsId,
- 'debt' => PurchaseOrderClass::DEBT_YES,
- 'actPrice<=' => 0,
- ], null, 'id', null, true);
- if (!empty($zeroList)) {
- foreach ($zeroList as $order) {
- $ids[intval($order->id ?? 0)] = 1;
- }
- }
- $cancelList = PurchaseOrderClass::getAllByCondition([
- 'ghsId' => $ghsId,
- 'debt' => PurchaseOrderClass::DEBT_YES,
- 'status' => PurchaseOrderClass::PURCHASE_ORDER_STATUS_CANCEL,
- ], null, 'id', null, true);
- if (!empty($cancelList)) {
- foreach ($cancelList as $order) {
- $ids[intval($order->id ?? 0)] = 1;
- }
- }
- return $ids;
- }
- /**
- * 【用途】清理不应再计待结的采购单。
- */
- public static function syncInvalidPurchaseDebtOrders($ghsId)
- {
- $ghsId = intval($ghsId);
- if ($ghsId <= 0) {
- return 0;
- }
- $invalidIds = self::collectInvalidPurchaseDebtOrderIds($ghsId);
- if (empty($invalidIds)) {
- return 0;
- }
- $fixed = 0;
- foreach (array_keys($invalidIds) as $orderId) {
- if ($orderId <= 0) {
- continue;
- }
- $order = PurchaseOrderClass::getById($orderId, true);
- if (empty($order) || intval($order->debt ?? 0) !== PurchaseOrderClass::DEBT_YES) {
- continue;
- }
- $order->debt = PurchaseOrderClass::DEBT_NO;
- $order->save(false, ['debt']);
- $fixed++;
- }
- return $fixed;
- }
- /**
- * 【用途】按采购待结订单重算 ownShop 侧 xhGhs 净 balance。
- * @return object
- */
- public static function mergeOwnShopGhsBalanceFromPurchaseOrdersIfNeeded($ghs, $writeBalanceChange = true, $forceRecalc = false)
- {
- return $ghs;
- }
- }
|