|
|
@@ -7,12 +7,17 @@ use bizGhs\custom\classes\AccountMoneyClass;
|
|
|
use bizGhs\custom\services\GhsRechargeSettleService;
|
|
|
use bizGhs\ghs\classes\GhsRechargeClass;
|
|
|
use bizGhs\shop\classes\MainClass;
|
|
|
+use bizGhs\shop\classes\ShopClass as GhsShopClass;
|
|
|
+use bizGhs\shop\classes\ShopMoneyClass;
|
|
|
use bizHd\ghs\classes\GhsClass;
|
|
|
use common\components\dict;
|
|
|
+use common\components\lakala\Lakala;
|
|
|
use common\components\noticeUtil;
|
|
|
+use common\components\orderSn;
|
|
|
use common\components\util;
|
|
|
use bizHd\base\classes\BaseClass;
|
|
|
use bizGhs\ghs\classes\GhsBalanceChangeClass;
|
|
|
+use Yii;
|
|
|
|
|
|
class CustomRechargeClass extends BaseClass
|
|
|
{
|
|
|
@@ -176,4 +181,252 @@ class CustomRechargeClass extends BaseClass
|
|
|
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 供货商后台:对已付款充值单退款(线上原路退 / 线下扣减余额)。
|
|
|
+ *
|
|
|
+ * @param int $rechargeId xhCustomRecharge.id
|
|
|
+ * @param object $shop 当前供货商门店
|
|
|
+ * @param object $staff 操作员工(记余额变动 staffId/staffName)
|
|
|
+ */
|
|
|
+ public static function refundPaidRecharge($rechargeId, $shop, $staff)
|
|
|
+ {
|
|
|
+ $rechargeId = intval($rechargeId);
|
|
|
+ if ($rechargeId <= 0) {
|
|
|
+ util::fail('参数错误');
|
|
|
+ }
|
|
|
+ $customRecharge = self::getLockById($rechargeId);
|
|
|
+ if (empty($customRecharge)) {
|
|
|
+ util::fail('没有找到充值记录');
|
|
|
+ }
|
|
|
+ $shopMainId = intval($shop->mainId ?? 0);
|
|
|
+ if (intval($customRecharge->mainId ?? 0) !== $shopMainId) {
|
|
|
+ util::fail('没有权限操作该充值记录');
|
|
|
+ }
|
|
|
+ if (intval($customRecharge->payStatus ?? 0) !== 1) {
|
|
|
+ util::fail('仅已付款的充值可退款');
|
|
|
+ }
|
|
|
+ if (self::isRechargeRefunded($customRecharge)) {
|
|
|
+ util::fail('该充值已退款');
|
|
|
+ }
|
|
|
+
|
|
|
+ $amount = bcadd((string)($customRecharge->amount ?? '0'), '0', 2);
|
|
|
+ if (bccomp($amount, '0', 2) <= 0) {
|
|
|
+ util::fail('充值金额有误');
|
|
|
+ }
|
|
|
+
|
|
|
+ $customId = intval($customRecharge->customId ?? 0);
|
|
|
+ $pair = GhsRechargeSettleService::lockAccountPair(['id' => $customId]);
|
|
|
+ $custom = $pair['custom'];
|
|
|
+ $ghs = $pair['ghs'];
|
|
|
+ if (empty($custom)) {
|
|
|
+ util::fail('没有找到客户');
|
|
|
+ }
|
|
|
+
|
|
|
+ $onlinePayYes = intval(dict::getDict('onlinePay', 'yes'));
|
|
|
+ $isOnline = intval($customRecharge->onlinePay ?? 0) === $onlinePayYes;
|
|
|
+ $payWay = intval($customRecharge->payWay ?? -1);
|
|
|
+ $wxPay = intval(dict::getDict('payWay', 'wxPay'));
|
|
|
+ $aliPay = intval(dict::getDict('payWay', 'alipay'));
|
|
|
+ $cashPay = intval(dict::getDict('payWay', 'cash'));
|
|
|
+
|
|
|
+ // 线上退款:先调支付渠道原路退回(拉卡拉商户取充值单所属门店)
|
|
|
+ if ($isOnline) {
|
|
|
+ if ($payWay !== $wxPay && $payWay !== $aliPay) {
|
|
|
+ util::fail('暂不支持该支付方式原路退款');
|
|
|
+ }
|
|
|
+ $returnCode = trim((string)($customRecharge->returnCode ?? ''));
|
|
|
+ if ($returnCode === '') {
|
|
|
+ util::fail('缺少支付流水号,无法原路退款');
|
|
|
+ }
|
|
|
+ $payShopId = intval($customRecharge->shopId ?? 0);
|
|
|
+ $payShop = $payShopId > 0 ? ShopClass::getById($payShopId, true) : $shop;
|
|
|
+ if (empty($payShop)) {
|
|
|
+ util::fail('没有找到收款门店');
|
|
|
+ }
|
|
|
+ self::refundOnlineByLakala($customRecharge, $payShop, $amount, $returnCode);
|
|
|
+ }
|
|
|
+
|
|
|
+ $staffId = intval($staff->id ?? 0);
|
|
|
+ $staffName = (string)($staff->name ?? '');
|
|
|
+ $newBalance = CustomClass::deductPairBalanceForRefund($custom, $ghs, $amount);
|
|
|
+
|
|
|
+ $capitalType = dict::getDict('capitalType', 'customRechargeRefund', 'id');
|
|
|
+ $fromType = dict::getDict('fromType', 'shop');
|
|
|
+ $orderSn = (string)($customRecharge->orderSn ?? '');
|
|
|
+ $customName = (string)($custom->name ?? '');
|
|
|
+ $ghsName = (string)($ghs->name ?? ($customRecharge->ghsName ?? ''));
|
|
|
+ $event = '充值退款(操作人:' . $staffName . ')单号:' . $orderSn;
|
|
|
+ $shopId = intval($shop->id ?? 0);
|
|
|
+ $mainId = intval($shop->mainId ?? 0);
|
|
|
+ $sjId = intval($shop->sjId ?? 0);
|
|
|
+ $onlinePayVal = $isOnline ? $onlinePayYes : intval(dict::getDict('onlinePay', 'not'));
|
|
|
+
|
|
|
+ CustomBalanceChangeClass::add([
|
|
|
+ 'customId' => $customId,
|
|
|
+ 'customName' => $customName,
|
|
|
+ 'relateId' => $rechargeId,
|
|
|
+ 'onlinePay' => $onlinePayVal,
|
|
|
+ 'ptStyle' => dict::getDict('ptStyle', 'ghs'),
|
|
|
+ 'capitalType' => $capitalType,
|
|
|
+ 'amount' => $amount,
|
|
|
+ 'balance' => $newBalance,
|
|
|
+ 'staffId' => $staffId,
|
|
|
+ 'staffName' => $staffName,
|
|
|
+ 'io' => 0,
|
|
|
+ 'side' => 0,
|
|
|
+ 'payWay' => $payWay,
|
|
|
+ 'fromType' => $fromType,
|
|
|
+ 'event' => $event,
|
|
|
+ 'mainId' => $mainId,
|
|
|
+ 'shopId' => $shopId,
|
|
|
+ 'sjId' => $sjId,
|
|
|
+ 'remark' => '',
|
|
|
+ ], true);
|
|
|
+
|
|
|
+ $customShopId = intval($custom->shopId ?? 0);
|
|
|
+ $customShop = GhsShopClass::getById($customShopId, true);
|
|
|
+ $ghsRechargeId = intval($customRecharge->ghsRechargeId ?? 0);
|
|
|
+ GhsBalanceChangeClass::add([
|
|
|
+ 'ghsId' => intval($ghs->id ?? 0),
|
|
|
+ 'ghsName' => $ghsName,
|
|
|
+ 'relateId' => $ghsRechargeId,
|
|
|
+ 'ptStyle' => dict::getDict('ptStyle', 'ghs'),
|
|
|
+ 'capitalType' => $capitalType,
|
|
|
+ 'amount' => $amount,
|
|
|
+ 'balance' => $newBalance,
|
|
|
+ 'staffId' => $staffId,
|
|
|
+ 'staffName' => $staffName,
|
|
|
+ 'io' => 0,
|
|
|
+ 'side' => 0,
|
|
|
+ 'onlinePay' => $onlinePayVal,
|
|
|
+ 'payWay' => $payWay,
|
|
|
+ 'fromType' => $fromType,
|
|
|
+ 'event' => $event,
|
|
|
+ 'sjId' => $customShop->sjId ?? 0,
|
|
|
+ 'mainId' => $customShop->mainId ?? 0,
|
|
|
+ 'shopId' => $customShopId,
|
|
|
+ 'remark' => '',
|
|
|
+ ], true);
|
|
|
+
|
|
|
+ // 线上充值曾增加门店 xhMain 余额,退款时对称扣减
|
|
|
+ if ($isOnline) {
|
|
|
+ $ghsShopId = intval($customRecharge->shopId ?? 0);
|
|
|
+ $ghsShop = ShopClass::getById($ghsShopId, true);
|
|
|
+ if (empty($ghsShop)) {
|
|
|
+ util::fail('没有找到供货商门店');
|
|
|
+ }
|
|
|
+ $ghsMain = MainClass::getLockById($ghsShop->mainId ?? 0);
|
|
|
+ if (empty($ghsMain)) {
|
|
|
+ util::fail('没有找到资产信息');
|
|
|
+ }
|
|
|
+ $originCapitalType = dict::getDict('capitalType', 'customRechargeToGhs', 'id');
|
|
|
+ $rechargeType = intval($customRecharge->rechargeType ?? 0);
|
|
|
+ if ($rechargeType === 1) {
|
|
|
+ $originCapitalType = dict::getDict('capitalType', 'ghsHelpCustomRechargeReturn', 'id');
|
|
|
+ }
|
|
|
+ ShopClass::customRechargeRefundReduceBalance($ghsMain, $ghsShop, $customRecharge, $originCapitalType, $staffName);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 线下现金充值:扣减 xhMain.money
|
|
|
+ if (!$isOnline && $payWay === $cashPay) {
|
|
|
+ $m = MainClass::getById($mainId, true, 'id, money');
|
|
|
+ if (!empty($m)) {
|
|
|
+ $moneyBefore = $m->money ?? 0;
|
|
|
+ $m->money = bcsub((string)$moneyBefore, $amount, 2);
|
|
|
+ $m->save(false, ['money']);
|
|
|
+ ShopMoneyClass::addData([
|
|
|
+ 'amount' => $amount,
|
|
|
+ 'balance' => $m->money,
|
|
|
+ 'io' => 0,
|
|
|
+ 'mainId' => $mainId,
|
|
|
+ 'capitalType' => $capitalType,
|
|
|
+ 'ptStyle' => dict::getDict('ptStyle', 'ghs'),
|
|
|
+ 'event' => '客户(' . $customName . ')充值退款' . $amount . '元',
|
|
|
+ 'remark' => '操作人:' . $staffName,
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ self::markRechargeRefunded($customRecharge);
|
|
|
+ if ($ghsRechargeId > 0) {
|
|
|
+ $ghsRecharge = GhsRechargeClass::getLockById($ghsRechargeId);
|
|
|
+ if (!empty($ghsRecharge)) {
|
|
|
+ self::markRechargeRefunded($ghsRecharge);
|
|
|
+ $ghsRecharge->balance = $newBalance;
|
|
|
+ $ghsRecharge->save(false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $customRecharge->balance = $newBalance;
|
|
|
+ $customRecharge->save(false);
|
|
|
+
|
|
|
+ return $customRecharge;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 充值记录是否已退款(兼容未加 refundStatus 列的环境) */
|
|
|
+ protected static function isRechargeRefunded($recharge)
|
|
|
+ {
|
|
|
+ if (empty($recharge)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (self::modelHasAttr($recharge, 'refundStatus')) {
|
|
|
+ return intval($recharge->refundStatus ?? 0) === 1;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 标记充值单已退款 */
|
|
|
+ protected static function markRechargeRefunded($recharge)
|
|
|
+ {
|
|
|
+ if (empty($recharge) || !self::modelHasAttr($recharge, 'refundStatus')) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ $recharge->refundStatus = 1;
|
|
|
+ $recharge->save(false, ['refundStatus']);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected static function modelHasAttr($model, $attr)
|
|
|
+ {
|
|
|
+ return is_object($model) && method_exists($model, 'hasAttribute') && $model->hasAttribute($attr);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 拉卡拉原路退款(微信/支付宝线上充值)。
|
|
|
+ */
|
|
|
+ protected static function refundOnlineByLakala($customRecharge, $shop, $amount, $returnCode)
|
|
|
+ {
|
|
|
+ $termNo = $shop->lklScanTermNo ?? '';
|
|
|
+ $payWay = intval($customRecharge->payWay ?? 0);
|
|
|
+ if ($payWay === intval(dict::getDict('payWay', 'alipay'))) {
|
|
|
+ $termNo = $shop->lklB2BTermNo ?? '';
|
|
|
+ }
|
|
|
+ if (empty($shop->lklSjNo) || empty($termNo)) {
|
|
|
+ util::fail('门店未配置拉卡拉商户信息');
|
|
|
+ }
|
|
|
+ $merchantPrivateKeyPath = Yii::getAlias('@vendor/lakala') . '/production/api_private_key.pem';
|
|
|
+ $lklCertificatePath = Yii::getAlias('@vendor/lakala') . '/production/lkl-apigw-v1.cer';
|
|
|
+ $params = [
|
|
|
+ 'appid' => 'OP00002119',
|
|
|
+ 'serial_no' => '018b08cfddbd',
|
|
|
+ 'merchant_no' => $shop->lklSjNo,
|
|
|
+ 'term_no' => $termNo,
|
|
|
+ 'merchantPrivateKeyPath' => $merchantPrivateKeyPath,
|
|
|
+ 'lklCertificatePath' => $lklCertificatePath,
|
|
|
+ ];
|
|
|
+ $laResource = new Lakala($params);
|
|
|
+ $refundSn = orderSn::getGhsCustomRechargeSn();
|
|
|
+ $refundFee = bcmul($amount, 100);
|
|
|
+ $aliParams = [
|
|
|
+ 'refundSn' => $refundSn,
|
|
|
+ 'orderSn' => $customRecharge->orderSn ?? '',
|
|
|
+ 'refundAmount' => $refundFee,
|
|
|
+ 'refundReason' => '充值退款',
|
|
|
+ 'thirdNo' => $returnCode,
|
|
|
+ ];
|
|
|
+ $response = $laResource->refund($aliParams);
|
|
|
+ if (!isset($response['code']) || $response['code'] != 'BBS00000') {
|
|
|
+ $errMsg = $response['msg'] ?? '退款失败';
|
|
|
+ util::fail('原路退款失败:' . $errMsg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
}
|