Files
ECShopX/tests/PointBundle/PointMemberShuyunOpenPlatformPointListServiceTest.php
wanghai 058673559c 4.7.0
2026-06-26 19:20:24 +08:00

320 lines
12 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace Tests\PointBundle;
use Dingo\Api\Exception\ResourceException;
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use MembersBundle\Services\MemberService;
use PointBundle\Services\PointMemberShuyunOpenPlatformPointListService;
use DistributionBundle\Repositories\DistributorRepository;
use ShuyunOpenPlatformBundle\Entities\CompanyShuyunOpenPlatformConfig;
use ShuyunOpenPlatformBundle\Repositories\CompanyShuyunOpenPlatformConfigRepository;
use ShuyunOpenPlatformBundle\Services\ShuyunOpenPlatformGatewayClientFactory;
use ShuyunOpenPlatformBundle\Services\ShuyunOpenPlatformGatewayShopIdResolver;
use ShuyunOpenPlatformBundle\Services\ShuyunOpenPlatformLoyaltyPointChangelogSearchService;
use ShuyunOpenPlatformBundle\Services\ShuyunOpenPlatformShopSyncService;
/**
* 计划 T-POINT-0610PointBundle 积分流水数云分支(列表服务 + Admin 辅助判定)。
*/
class PointMemberShuyunOpenPlatformPointListServiceTest extends \TestCase
{
/** T-POINT-06 */
public function testBuildListFromChangelogMapsRowsAndTotals(): void
{
$body = [
'code' => 10000,
'data' => [
'pageSize' => 10,
'totals' => 2,
'pageNum' => 1,
'list' => [
[
'changePoint' => 10,
'created' => '2022-06-15 09:33:13',
'source' => 'OTHER',
'desc' => '调试',
'partnerSequence' => 'O-1',
'recordId' => 386331442,
'point' => 160,
],
[
'changePoint' => -5,
'created' => '2022-06-16 10:00:00',
'source' => 'CONSUME',
'desc' => '扣减',
'partnerSequence' => '',
'recordId' => 386331443,
'point' => 155,
],
],
],
'msg' => '',
];
$changelog = $this->changelogSearchWithJsonBody($body);
$svc = new PointMemberShuyunOpenPlatformPointListService(
$changelog,
$this->mockConfigRepoEligible(),
$this->mockShopEligibility(true),
$this->createMock(MemberService::class),
);
$out = $svc->buildListFromChangelog(1, 999, 9301, 1, 10, null);
$this->assertSame(2, $out['total_count']);
$this->assertCount(2, $out['list']);
$this->assertSame('999', $out['list'][0]['user_id']);
$this->assertSame(10, $out['list'][0]['income']);
$this->assertSame(0, $out['list'][0]['outcome']);
$this->assertSame('income', $out['list'][0]['outin_type']);
$this->assertSame(160, $out['list'][0]['s_point']);
$this->assertSame(5, $out['list'][1]['outcome']);
$this->assertSame('outcome', $out['list'][1]['outin_type']);
}
/** T-POINT-06 — outin_type 过滤 */
public function testBuildListFromChangelogFiltersByOutinType(): void
{
$body = [
'code' => 10000,
'data' => [
'totals' => 2,
'pageNum' => 1,
'pageSize' => 10,
'list' => [
['changePoint' => 10, 'created' => '2022-01-01 00:00:00', 'source' => 'X', 'desc' => '', 'point' => 10],
['changePoint' => -3, 'created' => '2022-01-02 00:00:00', 'source' => 'Y', 'desc' => '', 'point' => 7],
],
],
'msg' => '',
];
$changelog = $this->changelogSearchWithJsonBody($body);
$svc = new PointMemberShuyunOpenPlatformPointListService(
$changelog,
$this->mockConfigRepoEligible(),
$this->mockShopEligibility(true),
$this->createMock(MemberService::class),
);
$out = $svc->buildListFromChangelog(1, 1, 1, 1, 10, 'outcome');
$this->assertCount(1, $out['list']);
$this->assertSame(3, $out['list'][0]['outcome']);
}
/** T-POINT-07 */
public function testAssertEligibleThrowsWhenNotEligible(): void
{
$repo = $this->createMock(CompanyShuyunOpenPlatformConfigRepository::class);
$cfg = $this->eligibleConfigEntity();
$repo->method('findOneByCompanyId')->with(7)->willReturn($cfg);
$sync = $this->createMock(ShuyunOpenPlatformShopSyncService::class);
$sync->method('isEligible')->with($cfg)->willReturn(false);
$svc = new PointMemberShuyunOpenPlatformPointListService(
$this->deadChangelogSearch(),
$repo,
$sync,
$this->createMock(MemberService::class),
);
$this->expectException(ResourceException::class);
$svc->assertEligibleOrThrow(7);
}
/** T-POINT-07 — 无配置行 */
public function testAssertEligibleThrowsWhenConfigMissing(): void
{
$repo = $this->createMock(CompanyShuyunOpenPlatformConfigRepository::class);
$repo->method('findOneByCompanyId')->willReturn(null);
$svc = new PointMemberShuyunOpenPlatformPointListService(
$this->deadChangelogSearch(),
$repo,
$this->createMock(ShuyunOpenPlatformShopSyncService::class),
$this->createMock(MemberService::class),
);
$this->expectException(ResourceException::class);
$svc->assertEligibleOrThrow(1);
}
/** T-POINT-08数云会员能力关闭时门面返回 false与 Front 先判此开关再达摩/本地一致)。 */
public function testTPoint08WhenMemberServiceSaysShuyunOffGateIsFalse(): void
{
$member = $this->createMock(MemberService::class);
$member->method('isShuyunOpenPlatformMemberEnabled')->willReturn(false);
$svc = new PointMemberShuyunOpenPlatformPointListService(
$this->deadChangelogSearch(),
$this->mockConfigRepoEligible(),
$this->mockShopEligibility(true),
$member,
);
$this->assertFalse($svc->isShuyunOpenPlatformMemberEnabled(100));
}
/** T-POINT-09 */
public function testTPoint09WhenShuyunOnIsTrue(): void
{
$member = $this->createMock(MemberService::class);
$member->method('isShuyunOpenPlatformMemberEnabled')->willReturn(true);
$svc = new PointMemberShuyunOpenPlatformPointListService(
$this->deadChangelogSearch(),
$this->mockConfigRepoEligible(),
$this->mockShopEligibility(true),
$member,
);
$this->assertTrue($svc->isShuyunOpenPlatformMemberEnabled(1));
}
/** T-POINT-10后管唯一定位单会员 */
public function testExtractSingleUserIdScalarAndArray(): void
{
$this->assertSame(5, PointMemberShuyunOpenPlatformPointListService::extractSingleUserId(['user_id' => 5]));
$this->assertSame(5, PointMemberShuyunOpenPlatformPointListService::extractSingleUserId(['user_id' => [5]]));
$this->assertNull(PointMemberShuyunOpenPlatformPointListService::extractSingleUserId(['user_id' => [5, 6]]));
$this->assertNull(PointMemberShuyunOpenPlatformPointListService::extractSingleUserId([]));
}
/** T-POINT-10日期筛选时走后管本地流水不调数云分页 */
public function testHasPointLogDateRangeFilter(): void
{
$this->assertTrue(PointMemberShuyunOpenPlatformPointListService::hasPointLogDateRangeFilter(['created|gte' => 1]));
$this->assertFalse(PointMemberShuyunOpenPlatformPointListService::hasPointLogDateRangeFilter(['company_id' => 1]));
}
public function testSearchFailureWrapsResourceException(): void
{
$stack = HandlerStack::create(new MockHandler([
new Response(200, [], '{"code":11008,"data":null,"msg":"accessToken invalid"}'),
]));
$client = new Client(['handler' => $stack, 'base_uri' => 'http://open-api.test/']);
config(['shuyun_open_platform.base_uri' => 'http://open-api.test']);
config(['shuyun_open_platform.default_plat_code' => 'OFFLINE']);
$changelog = new ShuyunOpenPlatformLoyaltyPointChangelogSearchService(
$this->mockConfigRepoEligible(),
$this->mockShopEligibility(true),
$this->mockDistributorRepoForPointList(1),
new ShuyunOpenPlatformGatewayShopIdResolver(),
$client,
new ShuyunOpenPlatformGatewayClientFactory(null),
);
$svc = new PointMemberShuyunOpenPlatformPointListService(
$changelog,
$this->mockConfigRepoEligible(),
$this->mockShopEligibility(true),
$this->createMock(MemberService::class),
);
$this->expectException(ResourceException::class);
$svc->buildListFromChangelog(1, 1, 1, 1, 10, null);
}
/**
* @param array<string, mixed> $body
*/
private function changelogSearchWithJsonBody(array $body): ShuyunOpenPlatformLoyaltyPointChangelogSearchService
{
config(['shuyun_open_platform.base_uri' => 'http://open-api.test']);
config(['shuyun_open_platform.default_plat_code' => 'OFFLINE']);
$stack = HandlerStack::create(new MockHandler([
new Response(200, [], json_encode($body, JSON_THROW_ON_ERROR)),
]));
$client = new Client(['handler' => $stack, 'base_uri' => 'http://open-api.test/']);
return new ShuyunOpenPlatformLoyaltyPointChangelogSearchService(
$this->mockConfigRepoEligible(),
$this->mockShopEligibility(true),
$this->mockDistributorRepoForPointList(1),
new ShuyunOpenPlatformGatewayShopIdResolver(),
$client,
new ShuyunOpenPlatformGatewayClientFactory(null),
);
}
private function deadChangelogSearch(): ShuyunOpenPlatformLoyaltyPointChangelogSearchService
{
config(['shuyun_open_platform.base_uri' => 'http://open-api.test']);
config(['shuyun_open_platform.default_plat_code' => 'OFFLINE']);
$client = new Client([
'handler' => HandlerStack::create(new MockHandler([])),
'base_uri' => 'http://open-api.test/',
]);
return new ShuyunOpenPlatformLoyaltyPointChangelogSearchService(
$this->mockConfigRepoEligible(),
$this->mockShopEligibility(true),
$this->mockDistributorRepoForPointList(1),
new ShuyunOpenPlatformGatewayShopIdResolver(),
$client,
new ShuyunOpenPlatformGatewayClientFactory(null),
);
}
/**
* 任意正整数 distributor_id 返回非虚拟店,便于列表单测覆盖多种 reg_distributor。
*/
private function mockDistributorRepoForPointList(int $companyId): DistributorRepository
{
$repo = $this->createMock(DistributorRepository::class);
$repo->method('getInfo')->willReturnCallback(static function (array $filter) use ($companyId): array {
$cid = (int) ($filter['company_id'] ?? 0);
$did = (int) ($filter['distributor_id'] ?? 0);
if ($cid !== $companyId || $did <= 0) {
return [];
}
return [
'company_id' => $companyId,
'distributor_id' => $did,
'distributor_self' => 0,
];
});
return $repo;
}
private function mockConfigRepoEligible(): CompanyShuyunOpenPlatformConfigRepository
{
$cfgRepo = $this->createMock(CompanyShuyunOpenPlatformConfigRepository::class);
$cfgRepo->method('findOneByCompanyId')->willReturn($this->eligibleConfigEntity());
return $cfgRepo;
}
private function mockShopEligibility(bool $ok): ShuyunOpenPlatformShopSyncService
{
$shopEligibility = $this->createMock(ShuyunOpenPlatformShopSyncService::class);
$shopEligibility->method('isEligible')->willReturn($ok);
return $shopEligibility;
}
private function eligibleConfigEntity(): CompanyShuyunOpenPlatformConfig
{
$e = new CompanyShuyunOpenPlatformConfig();
$e->setCompanyId(1);
$e->setAuthValue('av');
$e->setAppId('aid');
$e->setAppSecret('sec');
$e->setAccessToken('tok');
$e->setIsEnabled(1);
return $e;
}
}