add tmall refund item attribute parse test
This commit is contained in:
@@ -0,0 +1,434 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace HyperfTest\Cases\Platform\Tmall\EntityParse;
|
||||||
|
|
||||||
|
use App\Platform\Tmall\EntityParse\Refund;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use ReflectionClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tmall 退款子项 attribute 字段解析测试
|
||||||
|
*
|
||||||
|
* 使用两笔真实退款数据作为测试样本:
|
||||||
|
* - 样本A: 含 fundFlowInfo(资金流明细),商品单价 ¥399,退款 ¥177
|
||||||
|
* - 样本B: 不含 fundFlowInfo,商品单价 ¥1199,退款 ¥669
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
class RefundAttributeParseTest extends TestCase
|
||||||
|
{
|
||||||
|
private Refund $parser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 样本A: 含 fundFlowInfo 的完整退款 attribute
|
||||||
|
* 商品: 维C 250mg 橘子味 (SKU 5085821404607)
|
||||||
|
* 退款金额: ¥177.00, 支付宝 ¥154.89 + 优惠 ¥22.11
|
||||||
|
*/
|
||||||
|
private string $sampleA = ';fundFlowInfo:CASH^ALIPAY_FUND^支付宝^15489|OTHER_ASSETS^OTHER_ASSETS_GROUP^优惠^2211;bizCode:tmall.hk.refund;disputeRequest:1;leavesCat:50026924;apply_reason_text:不喜欢/不想要;itemBuyAmount:1;interceptItemListResult:[{\"subBizOrderId\"#3B5081613120736477027,\"interceptDate\"#3B\"Feb 24, 2026 1#3B48#3B02 PM\",\"logisticInterceptEnum\"#3B\"INTERCEPT_SUCCESS\"}];seller_batch:true;clj_zero_second_refund:1;cPartRefund:0;DBT:InterceptUnconsignRefund;_F_tlmType:B_taobao;sku:5085821404607|口味#3B橘子味#3A颜色分类#3B维C 250mg;sgr:0;bgmtc:2026-02-24 13#3B47#3B41;jibuBizCode:tmall.jibu;interceptType:clj;agreeSource:clj;shop_name:NordicNaturalsPro海外旗舰店;nrp:1;sync:0;pmtR:TAPP_USERCOUPON_SP^2211|;rp3:1;disputeTradeStatus:4;tmgSimpleZeroRefund:1;sars:skip;isVirtual:0;EXmrf:17700;warehouseRefund:1;price_protection:2026-02-24 13#3B47#3B45~2026-03-16 23#3B59#3B59;enfunddetail:1;agrExctT:1771912080140;pay_lock:system;lastOrder:0;tod:86400000;newRefund:rp2;opRole:daemon;newUltron:3;refundPostFee:0;products:timeoutrefund^;apply_init_refund_fee:17700;abilitySuccessFlag:1;apply_text_id:175001;userCredit:4;sdkCode:ali.china.tmall.tmallhk;b2c:1;_F_uplus:1;interceptStatus:2;agrExctd:1;sellerFlag:0;rootCat:50026800;tos:3;has_threshold_coupon:1;chnlObn:5081613120736477027;ol_tf:17700;percent_refund:1;part_refund:0;r_r_l:504;payMode:alipay;appName:rtee;fps:4;hasSellerMemo:0;workflowName:refund;threshold_instruction:{\"TAPP_USERCOUPON_SP\"#3B{\"fpAssetBizExt\"#3B\"fpOpId#3B10416813443042770\"}};abilityTemplateCode:WAREHOUSE_INTERCEPT_ABILITY^1^2|;seller_audit:0;sellerOpAbWarehouseIntercept:2;mainOrderPostFee:0;itemPrice:39900;toSellerFee:0;';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 样本B: 不含 fundFlowInfo 的退款 attribute
|
||||||
|
* 商品: 120粒装 (SKU 5112591851366)
|
||||||
|
* 退款金额: ¥669.00
|
||||||
|
*/
|
||||||
|
private string $sampleB = ';bizCode:tmall.hk.refund;disputeRequest:1;leavesCat:50026872;apply_reason_text:不喜欢/不想要;itemBuyAmount:1;interceptItemListResult:[{\"subBizOrderId\"#3B5080532763236889532,\"interceptDate\"#3B\"Feb 24, 2026 12#3B04#3B41 AM\",\"logisticInterceptEnum\"#3B\"INTERCEPT_SUCCESS\"}];seller_batch:true;clj_zero_second_refund:1;cPartRefund:0;DBT:InterceptUnconsignRefund;_F_tlmType:B_taobao;sku:5112591851366|颜色分类#3B120粒;sgr:0;bgmtc:2026-02-24 00#3B03#3B54;jibuBizCode:tmall.jibu;interceptType:clj;agreeSource:clj;shop_name:NordicNaturalsPro海外旗舰店;nrp:1;sync:0;pmtR:TAPP_USERCOUPON_SP^6589|;rp3:1;disputeTradeStatus:4;tmgSimpleZeroRefund:1;sars:skip;isVirtual:0;EXmrf:66900;warehouseRefund:1;price_protection:2026-02-24 00#3B04#3B01~2026-03-16 23#3B59#3B59;enfunddetail:1;agrExctT:1771862678950;pay_lock:system;lastOrder:0;tod:86400000;newRefund:rp2;opRole:daemon;newUltron:3;refundPostFee:0;products:timeoutrefund^;apply_init_refund_fee:66900;abilitySuccessFlag:1;apply_text_id:175001;userCredit:2;sdkCode:ali.china.tmall.tmallhk;b2c:1;interceptStatus:2;agrExctd:1;sellerFlag:0;rootCat:50026800;tos:3;has_threshold_coupon:1;chnlObn:5080532763236889532;ol_tf:66900;percent_refund:1;part_refund:0;r_r_l:504;payMode:alipay;appName:rtee;fps:4;hasSellerMemo:0;workflowName:refund;threshold_instruction:{\"TAPP_USERCOUPON_SP\"#3B{\"fpAssetBizExt\"#3B\"fpOpId#3B10414521188493295\"}};abilityTemplateCode:WAREHOUSE_INTERCEPT_ABILITY^1^2|;seller_audit:0;sellerOpAbWarehouseIntercept:2;mainOrderPostFee:0;itemPrice:119900;toSellerFee:0;';
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
// parseRefundItemAttribute 是纯解析方法,不依赖实例状态
|
||||||
|
// 通过 Reflection 绕过 EntityParse 的 protected 构造函数
|
||||||
|
$reflection = new ReflectionClass(Refund::class);
|
||||||
|
$this->parser = $reflection->newInstanceWithoutConstructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// 编码解码测试
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证 #3B → :(冒号) 解码正确
|
||||||
|
* bgmtc 原始值 "2026-02-24 13#3B47#3B41" 应解码为 "2026-02-24 13:47:41"
|
||||||
|
*/
|
||||||
|
public function testDecodeHashEncoding(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
|
||||||
|
$this->assertSame('2026-02-24 13:47:41', $result['bgmtc']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证 #3A → ;(分号) 解码正确
|
||||||
|
* SKU 属性分隔符 #3A 应解码为 ;
|
||||||
|
*/
|
||||||
|
public function testDecodeHashEncodingSemicolon(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
|
||||||
|
// SKU 的 properties 使用 ; 分隔后再用 : 切分
|
||||||
|
// 原始: 口味#3B橘子味#3A颜色分类#3B维C 250mg
|
||||||
|
// 解码: 口味:橘子味;颜色分类:维C 250mg
|
||||||
|
$this->assertSame('橘子味', $result['sku']['properties']['口味']);
|
||||||
|
$this->assertSame('维C 250mg', $result['sku']['properties']['颜色分类']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// 基本信息
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
public function testParseBasicInfo(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
|
||||||
|
$this->assertSame('tmall.hk.refund', $result['biz_code']);
|
||||||
|
$this->assertSame('ali.china.tmall.tmallhk', $result['sdk_code']);
|
||||||
|
$this->assertSame('NordicNaturalsPro海外旗舰店', $result['shop_name']);
|
||||||
|
$this->assertSame('refund', $result['workflow_name']);
|
||||||
|
$this->assertSame('daemon', $result['op_role']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// 商品信息 & SKU 解析
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 样本A SKU: 5085821404607|口味:橘子味;颜色分类:维C 250mg
|
||||||
|
*/
|
||||||
|
public function testParseSkuWithMultipleProperties(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
|
||||||
|
$this->assertSame('5085821404607', $result['sku']['sku_id']);
|
||||||
|
$this->assertCount(2, $result['sku']['properties']);
|
||||||
|
$this->assertSame('橘子味', $result['sku']['properties']['口味']);
|
||||||
|
$this->assertSame('维C 250mg', $result['sku']['properties']['颜色分类']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 样本B SKU: 5112591851366|颜色分类:120粒 (仅一个属性)
|
||||||
|
*/
|
||||||
|
public function testParseSkuWithSingleProperty(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute($this->sampleB);
|
||||||
|
|
||||||
|
$this->assertSame('5112591851366', $result['sku']['sku_id']);
|
||||||
|
$this->assertCount(1, $result['sku']['properties']);
|
||||||
|
$this->assertSame('120粒', $result['sku']['properties']['颜色分类']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testParseProductInfo(): void
|
||||||
|
{
|
||||||
|
$resultA = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
$resultB = $this->parser->parseRefundItemAttribute($this->sampleB);
|
||||||
|
|
||||||
|
// 购买数量
|
||||||
|
$this->assertSame(1, $resultA['item_buy_amount']);
|
||||||
|
|
||||||
|
// 商品单价 (分)
|
||||||
|
$this->assertSame(39900, $resultA['item_price']); // ¥399.00
|
||||||
|
$this->assertSame(119900, $resultB['item_price']); // ¥1,199.00
|
||||||
|
|
||||||
|
// 类目
|
||||||
|
$this->assertSame('50026924', $resultA['leaves_cat']);
|
||||||
|
$this->assertSame('50026800', $resultA['root_cat']);
|
||||||
|
$this->assertFalse($resultA['is_virtual']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// 退款金额
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
public function testParseRefundAmountsSampleA(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
|
||||||
|
$this->assertSame(17700, $result['apply_init_refund_fee']); // 申请退款 ¥177.00
|
||||||
|
$this->assertSame(17700, $result['ex_max_refund_fee']); // 最大可退 ¥177.00
|
||||||
|
$this->assertSame(17700, $result['online_refund_fee']); // 在线退款 ¥177.00
|
||||||
|
$this->assertSame(0, $result['refund_post_fee']);
|
||||||
|
$this->assertSame(0, $result['main_order_post_fee']);
|
||||||
|
$this->assertSame(0, $result['to_seller_fee']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testParseRefundAmountsSampleB(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute($this->sampleB);
|
||||||
|
|
||||||
|
$this->assertSame(66900, $result['apply_init_refund_fee']); // 申请退款 ¥669.00
|
||||||
|
$this->assertSame(66900, $result['ex_max_refund_fee']); // 最大可退 ¥669.00
|
||||||
|
$this->assertSame(66900, $result['online_refund_fee']); // 在线退款 ¥669.00
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// 退款原因与类型
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
public function testParseRefundReasonAndType(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
|
||||||
|
$this->assertSame('不喜欢/不想要', $result['apply_reason_text']);
|
||||||
|
$this->assertSame('175001', $result['apply_text_id']);
|
||||||
|
$this->assertSame(1, $result['dispute_request']);
|
||||||
|
$this->assertSame(4, $result['dispute_trade_status']);
|
||||||
|
$this->assertSame('InterceptUnconsignRefund', $result['dbt']); // 拦截未发货退款
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// 退款特征标识 (闪电退款判定的关键字段)
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clj_zero_second_refund = 1 表示0秒闪电退款
|
||||||
|
* 这是 fixInstantRefundOrders() 的判定依据
|
||||||
|
*/
|
||||||
|
public function testParseFlashRefundFlags(): void
|
||||||
|
{
|
||||||
|
$resultA = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
$resultB = $this->parser->parseRefundItemAttribute($this->sampleB);
|
||||||
|
|
||||||
|
// 两笔样本都是闪电退款
|
||||||
|
$this->assertTrue($resultA['clj_zero_second_refund']);
|
||||||
|
$this->assertTrue($resultB['clj_zero_second_refund']);
|
||||||
|
|
||||||
|
$this->assertTrue($resultA['tmg_simple_zero_refund']);
|
||||||
|
$this->assertTrue($resultA['warehouse_refund']);
|
||||||
|
$this->assertFalse($resultA['part_refund']);
|
||||||
|
$this->assertTrue($resultA['percent_refund']);
|
||||||
|
$this->assertSame('timeoutrefund^', $resultA['products']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// 资金流 (fundFlowInfo)
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 样本A 有 fundFlowInfo: 支付宝 ¥154.89 + 优惠 ¥22.11
|
||||||
|
*/
|
||||||
|
public function testParseFundFlowPresent(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
|
||||||
|
$this->assertCount(2, $result['fund_flow']);
|
||||||
|
|
||||||
|
// 支付宝现金
|
||||||
|
$this->assertSame('CASH', $result['fund_flow'][0]['type']);
|
||||||
|
$this->assertSame('ALIPAY_FUND', $result['fund_flow'][0]['group']);
|
||||||
|
$this->assertSame('支付宝', $result['fund_flow'][0]['name']);
|
||||||
|
$this->assertSame(15489, $result['fund_flow'][0]['amount']); // ¥154.89
|
||||||
|
|
||||||
|
// 优惠资产
|
||||||
|
$this->assertSame('OTHER_ASSETS', $result['fund_flow'][1]['type']);
|
||||||
|
$this->assertSame('OTHER_ASSETS_GROUP', $result['fund_flow'][1]['group']);
|
||||||
|
$this->assertSame('优惠', $result['fund_flow'][1]['name']);
|
||||||
|
$this->assertSame(2211, $result['fund_flow'][1]['amount']); // ¥22.11
|
||||||
|
|
||||||
|
$this->assertSame('alipay', $result['pay_mode']);
|
||||||
|
$this->assertSame('system', $result['pay_lock']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 样本B 没有 fundFlowInfo,fund_flow 应为空数组
|
||||||
|
*/
|
||||||
|
public function testParseFundFlowAbsent(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute($this->sampleB);
|
||||||
|
|
||||||
|
$this->assertSame([], $result['fund_flow']);
|
||||||
|
$this->assertSame('alipay', $result['pay_mode']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// 优惠信息 (pmtR / threshold)
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
public function testParsePromotions(): void
|
||||||
|
{
|
||||||
|
$resultA = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
$resultB = $this->parser->parseRefundItemAttribute($this->sampleB);
|
||||||
|
|
||||||
|
// 样本A: 优惠券 ¥22.11
|
||||||
|
$this->assertCount(1, $resultA['promotions']);
|
||||||
|
$this->assertSame('TAPP_USERCOUPON_SP', $resultA['promotions'][0]['type']);
|
||||||
|
$this->assertSame(2211, $resultA['promotions'][0]['amount']);
|
||||||
|
|
||||||
|
// 样本B: 优惠券 ¥65.89
|
||||||
|
$this->assertCount(1, $resultB['promotions']);
|
||||||
|
$this->assertSame('TAPP_USERCOUPON_SP', $resultB['promotions'][0]['type']);
|
||||||
|
$this->assertSame(6589, $resultB['promotions'][0]['amount']);
|
||||||
|
|
||||||
|
$this->assertTrue($resultA['has_threshold_coupon']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testParseThresholdInstruction(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
|
||||||
|
$this->assertIsArray($result['threshold_instruction']);
|
||||||
|
$this->assertArrayHasKey('TAPP_USERCOUPON_SP', $result['threshold_instruction']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// 价保
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
public function testParsePriceProtection(): void
|
||||||
|
{
|
||||||
|
$resultA = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
$resultB = $this->parser->parseRefundItemAttribute($this->sampleB);
|
||||||
|
|
||||||
|
// 样本A: 2026-02-24 13:47:45 ~ 2026-03-16 23:59:59
|
||||||
|
$this->assertSame('2026-02-24 13:47:45', $resultA['price_protection']['start']);
|
||||||
|
$this->assertSame('2026-03-16 23:59:59', $resultA['price_protection']['end']);
|
||||||
|
|
||||||
|
// 样本B: 2026-02-24 00:04:01 ~ 2026-03-16 23:59:59
|
||||||
|
$this->assertSame('2026-02-24 00:04:01', $resultB['price_protection']['start']);
|
||||||
|
$this->assertSame('2026-03-16 23:59:59', $resultB['price_protection']['end']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// 物流拦截
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
public function testParseInterceptInfo(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
|
||||||
|
$this->assertSame('clj', $result['intercept_type']); // 菜鸟拦截
|
||||||
|
$this->assertSame(2, $result['intercept_status']);
|
||||||
|
$this->assertTrue($result['ability_success_flag']);
|
||||||
|
$this->assertSame(2, $result['warehouse_intercept_op']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* interceptItemListResult 是编码后的 JSON
|
||||||
|
* 解码后应为包含拦截明细的数组
|
||||||
|
*/
|
||||||
|
public function testParseInterceptItemsJson(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
|
||||||
|
$this->assertIsArray($result['intercept_items']);
|
||||||
|
$this->assertCount(1, $result['intercept_items']);
|
||||||
|
$this->assertSame(5081613120736477027, $result['intercept_items'][0]['subBizOrderId']);
|
||||||
|
$this->assertSame('INTERCEPT_SUCCESS', $result['intercept_items'][0]['logisticInterceptEnum']);
|
||||||
|
$this->assertSame('Feb 24, 2026 1:48:02 PM', $result['intercept_items'][0]['interceptDate']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testParseInterceptItemsSampleB(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute($this->sampleB);
|
||||||
|
|
||||||
|
$this->assertIsArray($result['intercept_items']);
|
||||||
|
$this->assertCount(1, $result['intercept_items']);
|
||||||
|
$this->assertSame('INTERCEPT_SUCCESS', $result['intercept_items'][0]['logisticInterceptEnum']);
|
||||||
|
$this->assertSame('Feb 24, 2026 12:04:41 AM', $result['intercept_items'][0]['interceptDate']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// 卖家 / 买家
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
public function testParseSellerBuyerInfo(): void
|
||||||
|
{
|
||||||
|
$resultA = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
$resultB = $this->parser->parseRefundItemAttribute($this->sampleB);
|
||||||
|
|
||||||
|
$this->assertTrue($resultA['seller_batch']);
|
||||||
|
$this->assertSame(0, $resultA['seller_audit']);
|
||||||
|
$this->assertFalse($resultA['has_seller_memo']);
|
||||||
|
$this->assertSame('clj', $resultA['agree_source']); // 菜鸟自动同意
|
||||||
|
|
||||||
|
// 买家信用等级不同
|
||||||
|
$this->assertSame(4, $resultA['user_credit']);
|
||||||
|
$this->assertSame(2, $resultB['user_credit']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// 其他字段
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
public function testParseOtherFields(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
|
||||||
|
$this->assertSame('5081613120736477027', $result['channel_sub_order_id']);
|
||||||
|
$this->assertFalse($result['last_order']);
|
||||||
|
$this->assertTrue($result['b2c']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// 两笔样本的差异性对比
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认两笔样本的关键差异点
|
||||||
|
*/
|
||||||
|
public function testSampleDifferences(): void
|
||||||
|
{
|
||||||
|
$resultA = $this->parser->parseRefundItemAttribute($this->sampleA);
|
||||||
|
$resultB = $this->parser->parseRefundItemAttribute($this->sampleB);
|
||||||
|
|
||||||
|
// 金额差异
|
||||||
|
$this->assertSame(17700, $resultA['apply_init_refund_fee']); // ¥177
|
||||||
|
$this->assertSame(66900, $resultB['apply_init_refund_fee']); // ¥669
|
||||||
|
|
||||||
|
// 商品单价差异
|
||||||
|
$this->assertSame(39900, $resultA['item_price']); // ¥399
|
||||||
|
$this->assertSame(119900, $resultB['item_price']); // ¥1,199
|
||||||
|
|
||||||
|
// 资金流: A有,B无
|
||||||
|
$this->assertCount(2, $resultA['fund_flow']);
|
||||||
|
$this->assertCount(0, $resultB['fund_flow']);
|
||||||
|
|
||||||
|
// 优惠券金额差异
|
||||||
|
$this->assertSame(2211, $resultA['promotions'][0]['amount']); // ¥22.11
|
||||||
|
$this->assertSame(6589, $resultB['promotions'][0]['amount']); // ¥65.89
|
||||||
|
|
||||||
|
// 类目不同
|
||||||
|
$this->assertSame('50026924', $resultA['leaves_cat']);
|
||||||
|
$this->assertSame('50026872', $resultB['leaves_cat']);
|
||||||
|
|
||||||
|
// 共同特征: 都是闪电退款 + 仓库拦截成功
|
||||||
|
$this->assertTrue($resultA['clj_zero_second_refund']);
|
||||||
|
$this->assertTrue($resultB['clj_zero_second_refund']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
// 边界情况
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
public function testParseEmptyString(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute('');
|
||||||
|
|
||||||
|
$this->assertSame([], $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testParseSingleField(): void
|
||||||
|
{
|
||||||
|
$result = $this->parser->parseRefundItemAttribute(';bizCode:tmall.hk.refund;');
|
||||||
|
|
||||||
|
$this->assertSame('tmall.hk.refund', $result['biz_code']);
|
||||||
|
// 缺失字段使用默认值
|
||||||
|
$this->assertNull($result['shop_name']);
|
||||||
|
$this->assertSame(0, $result['item_price']);
|
||||||
|
$this->assertFalse($result['clj_zero_second_refund']);
|
||||||
|
$this->assertSame([], $result['fund_flow']);
|
||||||
|
$this->assertSame([], $result['promotions']);
|
||||||
|
$this->assertNull($result['price_protection']);
|
||||||
|
$this->assertNull($result['sku']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testParseNoLeadingSemicolon(): void
|
||||||
|
{
|
||||||
|
// attribute 可能不以 ; 开头
|
||||||
|
$result = $this->parser->parseRefundItemAttribute('bizCode:tmall.refund;shopName:test');
|
||||||
|
|
||||||
|
$this->assertSame('tmall.refund', $result['biz_code']);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user