- 416 rename Chairmen→Chairman; 419/421/422/423 убраны as unknown (строгие Zeus-типы, скаляры через Omit+override); 420 статусы через Zeus enum; 424/425 SuccessAlert/FailAlert в OrderCreateDialog; 417/418 дедуп normalizeTxHash/rethrowChainError в shared/chain-tx.util; 415 единый filter через InputType DTO (+ regen schema/zeus/SDK); 426/427 @OnEvent из cooptypes WalletContract (добавлены wallet-действия authwthd/declinewthd). Controller tsc зелёный; desktop vue-tsc — 2 pre-existing ошибки (q-tab :name=null). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -72,7 +72,7 @@ Workflow:
|
||||
pnpm jest tests/unit/marketplace/marketplace-onboarding-service.test.ts --runInBand
|
||||
```
|
||||
|
||||
`pnpm generate-schema` / `pnpm generate-client` — **не запускать локально**; та же memory/CPU полка вешает контейнер controller'а. Либо CI, либо пользователь сам когда контейнер остановлен.
|
||||
`pnpm generate-schema` / `pnpm generate-client` — **МОЖНО и НУЖНО запускать когда требуется** (разрешено пользователем явно). Любое изменение GraphQL-сигнатуры резолвера или типов контрактов обязано сопровождаться полным циклом регенерации (generate-schema → generate-client → sdk build, при правках cooptypes — ещё и cooptypes build), чтобы desktop получил актуальные типы. Не оставлять заглушку «до regen».
|
||||
|
||||
Перед коммитом достаточно `tsc --noEmit` (быстрый, не блокирует).
|
||||
|
||||
@@ -86,6 +86,12 @@ pnpm jest tests/unit/marketplace/marketplace-onboarding-service.test.ts --runInB
|
||||
|
||||
**Не дёргать `Mutations.Auth.Login` напрямую** — `LoginInput` ждёт `{email, now, signature}`, генерация подписи внутри SDK Client. Refresh: `Mutations.Auth.Refresh.mutation` с `{access_token, refresh_token}`. Канон используется в `blago-cli/src/session/index.ts` (loginInteractive) и в EMP-коннекторе `connectors/cooperative-tsk-login-connector` (Story 11.5).
|
||||
|
||||
## DRY — любое 2-кратное повторение выносится в общее (ОБЯЗАТЕЛЬНО)
|
||||
|
||||
Любой кусок кода (валидация, маппинг, guard, построение payload, helper-логика), повторённый **второй раз**, обязан быть вынесен в общее: `shared/`-helper / util / базовый класс (controller) или соответствующий FSD-слой `shared/` (desktop). Это **обязательное правило**, не рекомендация — не «то тут то там стряпать одно и то же».
|
||||
|
||||
**Триггер:** заметил второе вхождение → сразу выноси, не копируй. Применяется и в controller, и в desktop. (Зафиксировано пользователем в ревью PR #17 «Стол заказов».)
|
||||
|
||||
## Backend (controller) каноны
|
||||
|
||||
### 3 базовые роли — User / Member / Chairman
|
||||
|
||||
+1039
-182
File diff suppressed because it is too large
Load Diff
+7
-2
@@ -1,9 +1,14 @@
|
||||
import { Injectable, Inject, Logger } from '@nestjs/common';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { WalletContract } from 'cooptypes';
|
||||
import { PAYMENT_REPOSITORY, PaymentRepository } from '~/domain/gateway/repositories/payment.repository';
|
||||
import { PaymentStatusEnum } from '~/domain/gateway/enums/payment-status.enum';
|
||||
import type { ActionDomainInterface } from '~/domain/parser/interfaces/action-domain.interface';
|
||||
|
||||
const WALLET = WalletContract.contractName.production;
|
||||
const AUTH_WITHDRAW_EVENT = `action::${WALLET}::${WalletContract.Actions.AuthWithdraw.actionName}`;
|
||||
const DECLINE_WITHDRAW_EVENT = `action::${WALLET}::${WalletContract.Actions.DeclineWithdraw.actionName}`;
|
||||
|
||||
/**
|
||||
* Переключает статус исходящего платежа в зависимости от on-chain решения совета.
|
||||
*
|
||||
@@ -23,7 +28,7 @@ export class WithdrawAuthorizationListener {
|
||||
private readonly paymentRepository: PaymentRepository,
|
||||
) {}
|
||||
|
||||
@OnEvent('action::wallet::authwthd')
|
||||
@OnEvent(AUTH_WITHDRAW_EVENT)
|
||||
async onAuthWithdraw(action: ActionDomainInterface): Promise<void> {
|
||||
const withdraw_hash = action?.data?.withdraw_hash as string | undefined;
|
||||
if (!withdraw_hash) return;
|
||||
@@ -41,7 +46,7 @@ export class WithdrawAuthorizationListener {
|
||||
this.logger.log(`authwthd: платёж ${payment.id} → PENDING (совет авторизовал выплату)`);
|
||||
}
|
||||
|
||||
@OnEvent('action::wallet::declinewthd')
|
||||
@OnEvent(DECLINE_WITHDRAW_EVENT)
|
||||
async onDeclineWithdraw(action: ActionDomainInterface): Promise<void> {
|
||||
const withdraw_hash = action?.data?.withdraw_hash as string | undefined;
|
||||
if (!withdraw_hash) return;
|
||||
|
||||
+34
-1
@@ -1,4 +1,5 @@
|
||||
import { Field, ID, ObjectType, registerEnumType } from '@nestjs/graphql';
|
||||
import { Field, ID, InputType, ObjectType, registerEnumType } from '@nestjs/graphql';
|
||||
import { IsArray, IsEnum, IsOptional, IsString } from 'class-validator';
|
||||
import type { MarketplaceOutgoingPaymentRequestDomainEntity } from '../../domain/entities/marketplace-outgoing-payment-request.entity';
|
||||
|
||||
export enum MarketplaceOutgoingPaymentRequestStatusEnum {
|
||||
@@ -15,6 +16,38 @@ registerEnumType(MarketplaceOutgoingPaymentRequestStatusEnum, {
|
||||
'marketplace отображает результат только для истории.',
|
||||
});
|
||||
|
||||
@InputType('MarketplaceListOutgoingPaymentsAsSupplierFilterInput')
|
||||
export class MarketplaceListOutgoingPaymentsAsSupplierFilterInputDTO {
|
||||
@Field(() => [MarketplaceOutgoingPaymentRequestStatusEnum], {
|
||||
nullable: true,
|
||||
description: 'Фильтр по статусам выплат. Пусто — показывать все статусы.',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@IsEnum(MarketplaceOutgoingPaymentRequestStatusEnum, { each: true })
|
||||
statuses?: MarketplaceOutgoingPaymentRequestStatusEnum[];
|
||||
}
|
||||
|
||||
@InputType('MarketplaceListOutgoingPaymentsFilterInput')
|
||||
export class MarketplaceListOutgoingPaymentsFilterInputDTO {
|
||||
@Field(() => String, {
|
||||
nullable: true,
|
||||
description: 'Поставщик-получатель выплаты. Пусто — по всем поставщикам.',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
supplier_account?: string;
|
||||
|
||||
@Field(() => [MarketplaceOutgoingPaymentRequestStatusEnum], {
|
||||
nullable: true,
|
||||
description: 'Фильтр по статусам выплат. Пусто — показывать все статусы.',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@IsEnum(MarketplaceOutgoingPaymentRequestStatusEnum, { each: true })
|
||||
statuses?: MarketplaceOutgoingPaymentRequestStatusEnum[];
|
||||
}
|
||||
|
||||
@ObjectType('MarketplaceOutgoingPaymentRequest')
|
||||
export class MarketplaceOutgoingPaymentRequestDTO {
|
||||
@Field(() => ID)
|
||||
|
||||
+7
-7
@@ -8,9 +8,9 @@ import type { IMarketplaceCurrentMember } from '../dto/marketplace-current-membe
|
||||
import { mapUserRoleToCoreRoles } from '../membership/core-roles.mapper';
|
||||
import { mapCoreRolesToMarketplaceRoles } from '../membership/marketplace-roles.mapper';
|
||||
import {
|
||||
MARKETPLACE_KU_CHAIRMEN_SERVICE,
|
||||
type MarketplaceKuChairmenService,
|
||||
} from '../services/marketplace-ku-chairmen.service';
|
||||
MARKETPLACE_KU_CHAIRMAN_SERVICE,
|
||||
type MarketplaceKuChairmanService,
|
||||
} from '../services/marketplace-ku-chairman.service';
|
||||
import {
|
||||
MARKETPLACE_WHITELIST_SERVICE,
|
||||
type MarketplaceWhitelistService,
|
||||
@@ -37,8 +37,8 @@ export class MarketplaceMembershipGuard implements CanActivate {
|
||||
constructor(
|
||||
@Inject(MARKETPLACE_WHITELIST_SERVICE)
|
||||
private readonly whitelistService: MarketplaceWhitelistService,
|
||||
@Inject(MARKETPLACE_KU_CHAIRMEN_SERVICE)
|
||||
private readonly kuChairmenService: MarketplaceKuChairmenService
|
||||
@Inject(MARKETPLACE_KU_CHAIRMAN_SERVICE)
|
||||
private readonly kuChairmanService: MarketplaceKuChairmanService
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
@@ -62,11 +62,11 @@ export class MarketplaceMembershipGuard implements CanActivate {
|
||||
|
||||
const coreRoles = mapUserRoleToCoreRoles(user.role);
|
||||
// Story 3.1 / Эпик 2: оба источника берутся из dedicated-сервисов с
|
||||
// TTL-кешем (MarketplaceWhitelistService / MarketplaceKuChairmenService),
|
||||
// TTL-кешем (MarketplaceWhitelistService / MarketplaceKuChairmanService),
|
||||
// чтобы guard на каждом GraphQL-запросе не лез в RPC и в БД на N+1.
|
||||
const [isOfferer, isKuChairman] = await Promise.all([
|
||||
this.whitelistService.isOfferer(config.coopname, user.username),
|
||||
this.kuChairmenService.isKuChairman(config.coopname, user.username),
|
||||
this.kuChairmanService.isKuChairman(config.coopname, user.username),
|
||||
]);
|
||||
const marketplaceRoles = mapCoreRolesToMarketplaceRoles(coreRoles, {
|
||||
isOfferer,
|
||||
|
||||
+8
-8
@@ -33,9 +33,9 @@ import {
|
||||
MARKETPLACE_WHITELIST_SERVICE,
|
||||
} from './services/marketplace-whitelist.service';
|
||||
import {
|
||||
MarketplaceKuChairmenService,
|
||||
MARKETPLACE_KU_CHAIRMEN_SERVICE,
|
||||
} from './services/marketplace-ku-chairmen.service';
|
||||
MarketplaceKuChairmanService,
|
||||
MARKETPLACE_KU_CHAIRMAN_SERVICE,
|
||||
} from './services/marketplace-ku-chairman.service';
|
||||
import {
|
||||
MarketplaceVitrineService,
|
||||
MARKETPLACE_VITRINE_SERVICE,
|
||||
@@ -204,10 +204,10 @@ import { MarketplaceInventoryEntity } from '../infrastructure/entities/marketpla
|
||||
// Эпик 2 / Story 2.x — источник isKuChairman (trustee ИЛИ trusted
|
||||
// одного из branches кооператива) для marketplace-роли `operator`.
|
||||
{
|
||||
provide: MARKETPLACE_KU_CHAIRMEN_SERVICE,
|
||||
useClass: MarketplaceKuChairmenService,
|
||||
provide: MARKETPLACE_KU_CHAIRMAN_SERVICE,
|
||||
useClass: MarketplaceKuChairmanService,
|
||||
},
|
||||
MarketplaceKuChairmenService,
|
||||
MarketplaceKuChairmanService,
|
||||
{
|
||||
provide: MARKETPLACE_VITRINE_SERVICE,
|
||||
useClass: MarketplaceVitrineService,
|
||||
@@ -328,8 +328,8 @@ import { MarketplaceInventoryEntity } from '../infrastructure/entities/marketpla
|
||||
MarketplaceCoopAcceptanceService,
|
||||
MARKETPLACE_WHITELIST_SERVICE,
|
||||
MarketplaceWhitelistService,
|
||||
MARKETPLACE_KU_CHAIRMEN_SERVICE,
|
||||
MarketplaceKuChairmenService,
|
||||
MARKETPLACE_KU_CHAIRMAN_SERVICE,
|
||||
MarketplaceKuChairmanService,
|
||||
MARKETPLACE_VITRINE_SERVICE,
|
||||
MarketplaceVitrineService,
|
||||
MARKETPLACE_OFFER_SERVICE,
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ export type MarketplaceRole =
|
||||
* `MarketplaceWhitelistService.isOfferer`.
|
||||
*
|
||||
* `isKuChairman` — Эпик 2 (ПВЗ): пайщик имеет операционные полномочия
|
||||
* на хотя бы одном КУ кооператива. Источник — `MarketplaceKuChairmenService.isKuChairman`,
|
||||
* на хотя бы одном КУ кооператива. Источник — `MarketplaceKuChairmanService.isKuChairman`,
|
||||
* семантика «trustee ИЛИ trusted одного из branches» (trustee и trusted
|
||||
* равны в правах по столу ПВЗ — приёмка, выдача, маркировка, склад).
|
||||
*/
|
||||
|
||||
+7
-7
@@ -9,9 +9,9 @@ import { MarketplaceRoleGuard } from '../guards/marketplace-role.guard';
|
||||
import { canAccess } from '../access/marketplace-access-matrix';
|
||||
import type { MarketplaceRole } from '../membership/marketplace-roles.mapper';
|
||||
import {
|
||||
MARKETPLACE_KU_CHAIRMEN_SERVICE,
|
||||
type MarketplaceKuChairmenService,
|
||||
} from '../services/marketplace-ku-chairmen.service';
|
||||
MARKETPLACE_KU_CHAIRMAN_SERVICE,
|
||||
type MarketplaceKuChairmanService,
|
||||
} from '../services/marketplace-ku-chairman.service';
|
||||
import type { IMarketplaceCurrentMember } from '../dto/marketplace-current-member.dto';
|
||||
import {
|
||||
MarketplaceAplReceptionByIdInputDTO,
|
||||
@@ -52,8 +52,8 @@ export class MarketplaceAplReceptionResolver {
|
||||
private readonly service: MarketplaceAplReceptionService,
|
||||
@Inject(MARKETPLACE_APL_RECEPTION_REPOSITORY)
|
||||
private readonly receptionRepo: MarketplaceAplReceptionDomainRepository,
|
||||
@Inject(MARKETPLACE_KU_CHAIRMEN_SERVICE)
|
||||
private readonly kuChairmenService: MarketplaceKuChairmenService
|
||||
@Inject(MARKETPLACE_KU_CHAIRMAN_SERVICE)
|
||||
private readonly kuChairmanService: MarketplaceKuChairmanService
|
||||
) {}
|
||||
|
||||
@Mutation(() => MarketplaceAplReceptionResultDTO, {
|
||||
@@ -182,7 +182,7 @@ export class MarketplaceAplReceptionResolver {
|
||||
if (!reception || reception.coopname !== coopname) {
|
||||
throw new NotFoundException('Акт приёмки не найден.');
|
||||
}
|
||||
const isMember = await this.kuChairmenService.isMemberOfBranch(
|
||||
const isMember = await this.kuChairmanService.isMemberOfBranch(
|
||||
coopname,
|
||||
reception.braname,
|
||||
member.username
|
||||
@@ -219,7 +219,7 @@ export class MarketplaceAplReceptionResolver {
|
||||
// capability `Receiving:create`). Оператор только с правами своего КУ обязан
|
||||
// быть членом запрашиваемого участка, иначе утечёт лента приёмок чужого КУ.
|
||||
if (!canAccess(roles, 'Receiving', 'read:all')) {
|
||||
const isMember = await this.kuChairmenService.isMemberOfBranch(
|
||||
const isMember = await this.kuChairmanService.isMemberOfBranch(
|
||||
coopname,
|
||||
data.braname,
|
||||
member.username
|
||||
|
||||
+6
-6
@@ -9,9 +9,9 @@ import { MarketplaceRoleGuard } from '../guards/marketplace-role.guard';
|
||||
import { canAccess } from '../access/marketplace-access-matrix';
|
||||
import type { MarketplaceRole } from '../membership/marketplace-roles.mapper';
|
||||
import {
|
||||
MARKETPLACE_KU_CHAIRMEN_SERVICE,
|
||||
type MarketplaceKuChairmenService,
|
||||
} from '../services/marketplace-ku-chairmen.service';
|
||||
MARKETPLACE_KU_CHAIRMAN_SERVICE,
|
||||
type MarketplaceKuChairmanService,
|
||||
} from '../services/marketplace-ku-chairman.service';
|
||||
import type { IMarketplaceCurrentMember } from '../dto/marketplace-current-member.dto';
|
||||
import {
|
||||
MarketplaceInventoryItemDTO,
|
||||
@@ -45,8 +45,8 @@ export class MarketplaceInventoryResolver {
|
||||
private readonly labelService: MarketplaceInventoryLabelService,
|
||||
@Inject(MARKETPLACE_INVENTORY_REPOSITORY)
|
||||
private readonly inventoryRepo: MarketplaceInventoryDomainRepository,
|
||||
@Inject(MARKETPLACE_KU_CHAIRMEN_SERVICE)
|
||||
private readonly kuChairmenService: MarketplaceKuChairmenService
|
||||
@Inject(MARKETPLACE_KU_CHAIRMAN_SERVICE)
|
||||
private readonly kuChairmanService: MarketplaceKuChairmanService
|
||||
) {}
|
||||
|
||||
@Mutation(() => MarketplaceLabelInventoryResultDTO, {
|
||||
@@ -122,7 +122,7 @@ export class MarketplaceInventoryResolver {
|
||||
// `read:own-KU` (оператор/председатель КУ) ограничивается своими КУ.
|
||||
let branameFilter: string | string[] | undefined = data?.braname;
|
||||
if (!canAccess(roles, 'Warehouse', 'read:all')) {
|
||||
const ownBranames = await this.kuChairmenService.listBranamesForMember(
|
||||
const ownBranames = await this.kuChairmanService.listBranamesForMember(
|
||||
coopname,
|
||||
member.username
|
||||
);
|
||||
|
||||
+7
-7
@@ -9,9 +9,9 @@ import { MarketplaceRoleGuard } from '../guards/marketplace-role.guard';
|
||||
import { canAccess } from '../access/marketplace-access-matrix';
|
||||
import type { MarketplaceRole } from '../membership/marketplace-roles.mapper';
|
||||
import {
|
||||
MARKETPLACE_KU_CHAIRMEN_SERVICE,
|
||||
type MarketplaceKuChairmenService,
|
||||
} from '../services/marketplace-ku-chairmen.service';
|
||||
MARKETPLACE_KU_CHAIRMAN_SERVICE,
|
||||
type MarketplaceKuChairmanService,
|
||||
} from '../services/marketplace-ku-chairman.service';
|
||||
import type { IMarketplaceCurrentMember } from '../dto/marketplace-current-member.dto';
|
||||
import {
|
||||
MarketplaceFinalizeIssuanceInputDTO,
|
||||
@@ -51,8 +51,8 @@ export class MarketplaceIssuanceResolver {
|
||||
private readonly service: MarketplaceIssuanceService,
|
||||
@Inject(MARKETPLACE_ORDER_REPOSITORY)
|
||||
private readonly orderRepo: MarketplaceOrderDomainRepository,
|
||||
@Inject(MARKETPLACE_KU_CHAIRMEN_SERVICE)
|
||||
private readonly kuChairmenService: MarketplaceKuChairmenService
|
||||
@Inject(MARKETPLACE_KU_CHAIRMAN_SERVICE)
|
||||
private readonly kuChairmanService: MarketplaceKuChairmanService
|
||||
) {}
|
||||
|
||||
@Mutation(() => MarketplaceIssuanceResultDTO, {
|
||||
@@ -126,7 +126,7 @@ export class MarketplaceIssuanceResolver {
|
||||
if (!order || order.coopname !== coopname) {
|
||||
throw new NotFoundException('Заказ не найден.');
|
||||
}
|
||||
const isMember = await this.kuChairmenService.isMemberOfBranch(
|
||||
const isMember = await this.kuChairmanService.isMemberOfBranch(
|
||||
coopname,
|
||||
order.delivery_braname,
|
||||
member.username
|
||||
@@ -202,7 +202,7 @@ export class MarketplaceIssuanceResolver {
|
||||
// только с `read:own-KU` (оператор/председатель КУ) обязана быть членом
|
||||
// запрашиваемого участка, иначе утечёт лента выдач чужого КУ.
|
||||
if (!canAccess(roles, 'Issuance', 'read:all')) {
|
||||
const isMember = await this.kuChairmenService.isMemberOfBranch(
|
||||
const isMember = await this.kuChairmanService.isMemberOfBranch(
|
||||
coopname,
|
||||
data.delivery_braname,
|
||||
member.username
|
||||
|
||||
+6
-6
@@ -9,9 +9,9 @@ import { MarketplaceCurrentMemberDTO } from '../dto/marketplace-current-member.d
|
||||
import type { IMarketplaceCurrentMember } from '../dto/marketplace-current-member.dto';
|
||||
import { MarketplaceMembershipGuard } from '../guards/marketplace-membership.guard';
|
||||
import {
|
||||
MARKETPLACE_KU_CHAIRMEN_SERVICE,
|
||||
type MarketplaceKuChairmenService,
|
||||
} from '../services/marketplace-ku-chairmen.service';
|
||||
MARKETPLACE_KU_CHAIRMAN_SERVICE,
|
||||
type MarketplaceKuChairmanService,
|
||||
} from '../services/marketplace-ku-chairman.service';
|
||||
|
||||
/**
|
||||
* Story 1.3: тестовый whoami-эндпоинт расширения marketplace.
|
||||
@@ -25,8 +25,8 @@ import {
|
||||
@Injectable()
|
||||
export class MarketplaceMembershipResolver {
|
||||
constructor(
|
||||
@Inject(MARKETPLACE_KU_CHAIRMEN_SERVICE)
|
||||
private readonly kuChairmenService: MarketplaceKuChairmenService
|
||||
@Inject(MARKETPLACE_KU_CHAIRMAN_SERVICE)
|
||||
private readonly kuChairmanService: MarketplaceKuChairmanService
|
||||
) {}
|
||||
|
||||
@Query(() => MarketplaceCurrentMemberDTO, {
|
||||
@@ -37,7 +37,7 @@ export class MarketplaceMembershipResolver {
|
||||
async marketplaceWhoAmI(
|
||||
@CurrentMarketplaceMember() currentMember: IMarketplaceCurrentMember
|
||||
): Promise<MarketplaceCurrentMemberDTO> {
|
||||
const branches = await this.kuChairmenService.listBranamesForMember(
|
||||
const branches = await this.kuChairmanService.listBranamesForMember(
|
||||
config.coopname,
|
||||
currentMember.username
|
||||
);
|
||||
|
||||
+9
-15
@@ -8,8 +8,9 @@ import { MarketplaceMembershipGuard } from '../guards/marketplace-membership.gua
|
||||
import { MarketplaceRoleGuard } from '../guards/marketplace-role.guard';
|
||||
import type { IMarketplaceCurrentMember } from '../dto/marketplace-current-member.dto';
|
||||
import {
|
||||
MarketplaceListOutgoingPaymentsAsSupplierFilterInputDTO,
|
||||
MarketplaceListOutgoingPaymentsFilterInputDTO,
|
||||
MarketplaceOutgoingPaymentRequestDTO,
|
||||
MarketplaceOutgoingPaymentRequestStatusEnum,
|
||||
toMarketplaceOutgoingPaymentRequestDTO,
|
||||
} from '../dto/marketplace-outgoing-payment.dto';
|
||||
import {
|
||||
@@ -40,16 +41,13 @@ export class MarketplaceOutgoingPaymentResolver {
|
||||
@UseGuards(GqlJwtAuthGuard, MarketplaceMembershipGuard)
|
||||
async marketplaceListOutgoingPaymentsAsSupplier(
|
||||
@CurrentMarketplaceMember() member: IMarketplaceCurrentMember,
|
||||
@Args('statuses', {
|
||||
type: () => [MarketplaceOutgoingPaymentRequestStatusEnum],
|
||||
nullable: true,
|
||||
})
|
||||
statuses?: MarketplaceOutgoingPaymentRequestStatusEnum[]
|
||||
@Args('filter', { nullable: true })
|
||||
filter?: MarketplaceListOutgoingPaymentsAsSupplierFilterInputDTO
|
||||
): Promise<MarketplaceOutgoingPaymentRequestDTO[]> {
|
||||
const list = await this.paymentRepo.listByPayee(
|
||||
config.coopname,
|
||||
member.username,
|
||||
statuses as unknown as MarketplaceOutgoingPaymentRequestStatus[] | undefined
|
||||
filter?.statuses as MarketplaceOutgoingPaymentRequestStatus[] | undefined
|
||||
);
|
||||
return list.map(toMarketplaceOutgoingPaymentRequestDTO);
|
||||
}
|
||||
@@ -62,16 +60,12 @@ export class MarketplaceOutgoingPaymentResolver {
|
||||
@UseGuards(GqlJwtAuthGuard, MarketplaceMembershipGuard, MarketplaceRoleGuard)
|
||||
@RequireMarketplaceAccess('Payment', 'read:all')
|
||||
async marketplaceListOutgoingPayments(
|
||||
@Args('supplier_account', { nullable: true }) supplier_account?: string,
|
||||
@Args('statuses', {
|
||||
type: () => [MarketplaceOutgoingPaymentRequestStatusEnum],
|
||||
nullable: true,
|
||||
})
|
||||
statuses?: MarketplaceOutgoingPaymentRequestStatusEnum[]
|
||||
@Args('filter', { nullable: true })
|
||||
filter?: MarketplaceListOutgoingPaymentsFilterInputDTO
|
||||
): Promise<MarketplaceOutgoingPaymentRequestDTO[]> {
|
||||
const list = await this.paymentRepo.listAll(config.coopname, {
|
||||
payee_account: supplier_account ?? undefined,
|
||||
statuses: statuses as unknown as MarketplaceOutgoingPaymentRequestStatus[] | undefined,
|
||||
payee_account: filter?.supplier_account ?? undefined,
|
||||
statuses: filter?.statuses as MarketplaceOutgoingPaymentRequestStatus[] | undefined,
|
||||
});
|
||||
return list.map(toMarketplaceOutgoingPaymentRequestDTO);
|
||||
}
|
||||
|
||||
+8
-8
@@ -22,9 +22,9 @@ import {
|
||||
} from '../dto/marketplace-return-claim.dto';
|
||||
import { MarketplaceReturnClaimService } from '../services/marketplace-return-claim.service';
|
||||
import {
|
||||
MARKETPLACE_KU_CHAIRMEN_SERVICE,
|
||||
type MarketplaceKuChairmenService,
|
||||
} from '../services/marketplace-ku-chairmen.service';
|
||||
MARKETPLACE_KU_CHAIRMAN_SERVICE,
|
||||
type MarketplaceKuChairmanService,
|
||||
} from '../services/marketplace-ku-chairman.service';
|
||||
import { Inject } from '@nestjs/common';
|
||||
import { toMarketplaceReturnClaimDTO } from './marketplace-return-claim.mapper';
|
||||
|
||||
@@ -53,8 +53,8 @@ function toGeneratedDocumentDTO(e: DocumentDomainEntity): GeneratedDocumentDTO {
|
||||
export class MarketplaceReturnClaimResolver {
|
||||
constructor(
|
||||
private readonly service: MarketplaceReturnClaimService,
|
||||
@Inject(MARKETPLACE_KU_CHAIRMEN_SERVICE)
|
||||
private readonly kuChairmenService: MarketplaceKuChairmenService
|
||||
@Inject(MARKETPLACE_KU_CHAIRMAN_SERVICE)
|
||||
private readonly kuChairmanService: MarketplaceKuChairmanService
|
||||
) {}
|
||||
|
||||
@Query(() => GeneratedDocumentDTO, {
|
||||
@@ -220,8 +220,8 @@ export class MarketplaceReturnClaimResolver {
|
||||
): Promise<MarketplaceReturnClaimDTO[]> {
|
||||
// Ownership `:own-KU` — пайщик должен быть trustee или trusted
|
||||
// именно того КУ, к которому привязано заявление. Проверка идёт
|
||||
// через единый источник истины состава КУ (MarketplaceKuChairmenService).
|
||||
const isMember = await this.kuChairmenService.isMemberOfBranch(
|
||||
// через единый источник истины состава КУ (MarketplaceKuChairmanService).
|
||||
const isMember = await this.kuChairmanService.isMemberOfBranch(
|
||||
config.coopname,
|
||||
data.delivery_braname,
|
||||
member.username
|
||||
@@ -256,7 +256,7 @@ export class MarketplaceReturnClaimResolver {
|
||||
const isOwnerOrderer = claim.orderer_account === member.username;
|
||||
const isOperatorOfDeliveryKu =
|
||||
member.marketplace_roles.includes('operator') &&
|
||||
(await this.kuChairmenService.isMemberOfBranch(
|
||||
(await this.kuChairmanService.isMemberOfBranch(
|
||||
config.coopname,
|
||||
claim.delivery_braname,
|
||||
member.username
|
||||
|
||||
+6
-6
@@ -9,9 +9,9 @@ import { MarketplaceRoleGuard } from '../guards/marketplace-role.guard';
|
||||
import { canAccess } from '../access/marketplace-access-matrix';
|
||||
import type { MarketplaceRole } from '../membership/marketplace-roles.mapper';
|
||||
import {
|
||||
MARKETPLACE_KU_CHAIRMEN_SERVICE,
|
||||
type MarketplaceKuChairmenService,
|
||||
} from '../services/marketplace-ku-chairmen.service';
|
||||
MARKETPLACE_KU_CHAIRMAN_SERVICE,
|
||||
type MarketplaceKuChairmanService,
|
||||
} from '../services/marketplace-ku-chairman.service';
|
||||
import type { IMarketplaceCurrentMember } from '../dto/marketplace-current-member.dto';
|
||||
import {
|
||||
MarketplaceCreateShipmentInputDTO,
|
||||
@@ -45,8 +45,8 @@ export class MarketplaceShipmentResolver {
|
||||
private readonly createService: MarketplaceShipmentCreateService,
|
||||
@Inject(MARKETPLACE_SHIPMENT_REPOSITORY)
|
||||
private readonly shipmentRepo: MarketplaceShipmentDomainRepository,
|
||||
@Inject(MARKETPLACE_KU_CHAIRMEN_SERVICE)
|
||||
private readonly kuChairmenService: MarketplaceKuChairmenService
|
||||
@Inject(MARKETPLACE_KU_CHAIRMAN_SERVICE)
|
||||
private readonly kuChairmanService: MarketplaceKuChairmanService
|
||||
) {}
|
||||
|
||||
@Mutation(() => MarketplaceCreateShipmentResultDTO, {
|
||||
@@ -119,7 +119,7 @@ export class MarketplaceShipmentResolver {
|
||||
// только с `read:own-KU` (оператор/председатель КУ) обязана быть членом
|
||||
// запрашиваемого участка, иначе утечёт лента поставок чужого КУ.
|
||||
if (!canAccess(roles, 'Shipment', 'read:all')) {
|
||||
const isMember = await this.kuChairmenService.isMemberOfBranch(
|
||||
const isMember = await this.kuChairmanService.isMemberOfBranch(
|
||||
coopname,
|
||||
data.braname,
|
||||
member.username
|
||||
|
||||
+13
-13
@@ -1,4 +1,4 @@
|
||||
import { MarketplaceKuChairmenService } from './marketplace-ku-chairmen.service';
|
||||
import { MarketplaceKuChairmanService } from './marketplace-ku-chairman.service';
|
||||
import type { BranchBlockchainPort } from '~/domain/branch/interfaces/branch-blockchain.port';
|
||||
|
||||
function buildPort(branches: Array<{ braname: string; trustee: string; trusted: string[] }>) {
|
||||
@@ -10,14 +10,14 @@ function buildPort(branches: Array<{ braname: string; trustee: string; trusted:
|
||||
return port as BranchBlockchainPort & { getBranches: jest.Mock };
|
||||
}
|
||||
|
||||
describe('MarketplaceKuChairmenService', () => {
|
||||
describe('MarketplaceKuChairmanService', () => {
|
||||
describe('isKuChairman', () => {
|
||||
it('возвращает true для trustee любого КУ', async () => {
|
||||
const port = buildPort([
|
||||
{ braname: 'krg', trustee: 'chairkrg', trusted: ['opkrg'] },
|
||||
{ braname: 'myt', trustee: 'chairmyt', trusted: [] },
|
||||
]);
|
||||
const service = new MarketplaceKuChairmenService(port);
|
||||
const service = new MarketplaceKuChairmanService(port);
|
||||
|
||||
expect(await service.isKuChairman('voskhod', 'chairkrg')).toBe(true);
|
||||
expect(await service.isKuChairman('voskhod', 'chairmyt')).toBe(true);
|
||||
@@ -27,7 +27,7 @@ describe('MarketplaceKuChairmenService', () => {
|
||||
const port = buildPort([
|
||||
{ braname: 'krg', trustee: 'chairkrg', trusted: ['opkrg', 'trustedkrg'] },
|
||||
]);
|
||||
const service = new MarketplaceKuChairmenService(port);
|
||||
const service = new MarketplaceKuChairmanService(port);
|
||||
|
||||
expect(await service.isKuChairman('voskhod', 'opkrg')).toBe(true);
|
||||
expect(await service.isKuChairman('voskhod', 'trustedkrg')).toBe(true);
|
||||
@@ -37,7 +37,7 @@ describe('MarketplaceKuChairmenService', () => {
|
||||
const port = buildPort([
|
||||
{ braname: 'krg', trustee: 'chairkrg', trusted: ['opkrg'] },
|
||||
]);
|
||||
const service = new MarketplaceKuChairmenService(port);
|
||||
const service = new MarketplaceKuChairmanService(port);
|
||||
|
||||
expect(await service.isKuChairman('voskhod', 'ivanpetrov')).toBe(false);
|
||||
});
|
||||
@@ -46,7 +46,7 @@ describe('MarketplaceKuChairmenService', () => {
|
||||
const port = buildPort([
|
||||
{ braname: 'krg', trustee: 'chairkrg', trusted: [] },
|
||||
]);
|
||||
const service = new MarketplaceKuChairmenService(port);
|
||||
const service = new MarketplaceKuChairmanService(port);
|
||||
|
||||
await service.isKuChairman('voskhod', 'chairkrg');
|
||||
await service.isKuChairman('voskhod', 'someoneelse');
|
||||
@@ -59,7 +59,7 @@ describe('MarketplaceKuChairmenService', () => {
|
||||
const port = buildPort([
|
||||
{ braname: 'krg', trustee: 'chairkrg', trusted: [] },
|
||||
]);
|
||||
const service = new MarketplaceKuChairmenService(port);
|
||||
const service = new MarketplaceKuChairmanService(port);
|
||||
|
||||
await service.isKuChairman('voskhod', 'chairkrg');
|
||||
service.invalidate('voskhod');
|
||||
@@ -75,7 +75,7 @@ describe('MarketplaceKuChairmenService', () => {
|
||||
{ braname: 'krg', trustee: 'chairkrg', trusted: ['opkrg'] },
|
||||
{ braname: 'myt', trustee: 'chairmyt', trusted: [] },
|
||||
]);
|
||||
const service = new MarketplaceKuChairmenService(port);
|
||||
const service = new MarketplaceKuChairmanService(port);
|
||||
|
||||
expect(await service.isMemberOfBranch('voskhod', 'krg', 'chairkrg')).toBe(true);
|
||||
expect(await service.isMemberOfBranch('voskhod', 'krg', 'opkrg')).toBe(true);
|
||||
@@ -90,7 +90,7 @@ describe('MarketplaceKuChairmenService', () => {
|
||||
const port = buildPort([
|
||||
{ braname: 'krg', trustee: 'chairkrg', trusted: ['opkrg', 'trustedkrg'] },
|
||||
]);
|
||||
const service = new MarketplaceKuChairmenService(port);
|
||||
const service = new MarketplaceKuChairmanService(port);
|
||||
|
||||
expect(await service.listOperatorsOfBranch('voskhod', 'krg')).toEqual([
|
||||
'chairkrg',
|
||||
@@ -101,7 +101,7 @@ describe('MarketplaceKuChairmenService', () => {
|
||||
|
||||
it('пустой список для несуществующего КУ', async () => {
|
||||
const port = buildPort([]);
|
||||
const service = new MarketplaceKuChairmenService(port);
|
||||
const service = new MarketplaceKuChairmanService(port);
|
||||
|
||||
expect(await service.listOperatorsOfBranch('voskhod', 'nope')).toEqual([]);
|
||||
});
|
||||
@@ -114,7 +114,7 @@ describe('MarketplaceKuChairmenService', () => {
|
||||
{ braname: 'myt', trustee: 'chairmyt', trusted: [] },
|
||||
{ braname: 'odn', trustee: 'chairodn', trusted: ['ekaterina'] },
|
||||
]);
|
||||
const service = new MarketplaceKuChairmenService(port);
|
||||
const service = new MarketplaceKuChairmanService(port);
|
||||
|
||||
expect(await service.listBranamesForMember('voskhod', 'ekaterina')).toEqual(['krg', 'odn']);
|
||||
expect(await service.listBranamesForMember('voskhod', 'chairmyt')).toEqual(['myt']);
|
||||
@@ -127,14 +127,14 @@ describe('MarketplaceKuChairmenService', () => {
|
||||
const port = buildPort([
|
||||
{ braname: 'krg', trustee: 'chairkrg', trusted: ['opkrg'] },
|
||||
]);
|
||||
const service = new MarketplaceKuChairmenService(port);
|
||||
const service = new MarketplaceKuChairmanService(port);
|
||||
|
||||
expect(await service.getTrusteeOfBranch('voskhod', 'krg')).toBe('chairkrg');
|
||||
});
|
||||
|
||||
it('возвращает null для несуществующего', async () => {
|
||||
const port = buildPort([]);
|
||||
const service = new MarketplaceKuChairmenService(port);
|
||||
const service = new MarketplaceKuChairmanService(port);
|
||||
|
||||
expect(await service.getTrusteeOfBranch('voskhod', 'nope')).toBeNull();
|
||||
});
|
||||
+3
-3
@@ -7,7 +7,7 @@ import {
|
||||
type BranchBlockchainPort,
|
||||
} from '~/domain/branch/interfaces/branch-blockchain.port';
|
||||
|
||||
export const MARKETPLACE_KU_CHAIRMEN_SERVICE = Symbol('MARKETPLACE_KU_CHAIRMEN_SERVICE');
|
||||
export const MARKETPLACE_KU_CHAIRMAN_SERVICE = Symbol('MARKETPLACE_KU_CHAIRMAN_SERVICE');
|
||||
|
||||
interface IBranchesCacheEntry {
|
||||
branches: BranchContract.Tables.Branches.IBranch[];
|
||||
@@ -41,7 +41,7 @@ interface IBranchesCacheEntry {
|
||||
* состав КУ, дёргают `invalidate(coopname)`.
|
||||
*/
|
||||
@Injectable()
|
||||
export class MarketplaceKuChairmenService {
|
||||
export class MarketplaceKuChairmanService {
|
||||
private static readonly BRANCHES_CACHE_TTL_MS = 60_000;
|
||||
private readonly branchesCache = new Map<string, IBranchesCacheEntry>();
|
||||
|
||||
@@ -114,7 +114,7 @@ export class MarketplaceKuChairmenService {
|
||||
const branches = await this.branchPort.getBranches(coopname);
|
||||
this.branchesCache.set(coopname, {
|
||||
branches,
|
||||
expires_at: now + MarketplaceKuChairmenService.BRANCHES_CACHE_TTL_MS,
|
||||
expires_at: now + MarketplaceKuChairmanService.BRANCHES_CACHE_TTL_MS,
|
||||
});
|
||||
return branches;
|
||||
}
|
||||
+6
-6
@@ -7,9 +7,9 @@ import { NOVU_WORKFLOW_PORT, type NovuWorkflowPort } from '~/domain/notification
|
||||
import { ACCOUNT_DATA_PORT, type AccountDataPort } from '~/domain/account/ports/account-data.port';
|
||||
import type { WorkflowTriggerDomainInterface } from '~/domain/notification/interfaces/workflow-trigger-domain.interface';
|
||||
import {
|
||||
MARKETPLACE_KU_CHAIRMEN_SERVICE,
|
||||
type MarketplaceKuChairmenService,
|
||||
} from './marketplace-ku-chairmen.service';
|
||||
MARKETPLACE_KU_CHAIRMAN_SERVICE,
|
||||
type MarketplaceKuChairmanService,
|
||||
} from './marketplace-ku-chairman.service';
|
||||
import {
|
||||
MARKETPLACE_APL_SUPPLIER_SIGN_REQUEST_EVENT,
|
||||
MARKETPLACE_CASHIER_NEW_PAYMENT_EVENT,
|
||||
@@ -51,8 +51,8 @@ export class MarketplaceNotificationService implements OnModuleInit {
|
||||
private readonly novuWorkflowPort: NovuWorkflowPort,
|
||||
@Inject(ACCOUNT_DATA_PORT)
|
||||
private readonly accountPort: AccountDataPort,
|
||||
@Inject(MARKETPLACE_KU_CHAIRMEN_SERVICE)
|
||||
private readonly kuChairmenService: MarketplaceKuChairmenService,
|
||||
@Inject(MARKETPLACE_KU_CHAIRMAN_SERVICE)
|
||||
private readonly kuChairmanService: MarketplaceKuChairmanService,
|
||||
private readonly logger: WinstonLoggerService
|
||||
) {
|
||||
this.logger.setContext(MarketplaceNotificationService.name);
|
||||
@@ -236,7 +236,7 @@ export class MarketplaceNotificationService implements OnModuleInit {
|
||||
// равны в правах по столу ПВЗ, новый return-claim видят все. Veerom
|
||||
// (несколько Novu-триггеров) сохраняет инвариант «никто не пропустил»
|
||||
// без ввода понятия «главный получатель уведомления».
|
||||
const operators = await this.kuChairmenService.listOperatorsOfBranch(
|
||||
const operators = await this.kuChairmanService.listOperatorsOfBranch(
|
||||
event.coopname,
|
||||
event.delivery_braname
|
||||
);
|
||||
|
||||
+6
-37
@@ -13,6 +13,7 @@ import {
|
||||
type MarketplaceCanonicalBlockchainPort,
|
||||
} from '../../domain/ports/marketplace-canonical-blockchain.port';
|
||||
import type { MarketplaceOrderDomainEntity } from '../../domain/entities/marketplace-order.entity';
|
||||
import { normalizeChainTxHash, rethrowChainError } from '../shared/chain-tx.util';
|
||||
|
||||
export interface MarketplaceOrderCancelInputDto {
|
||||
/** coopname кооператива. Берётся из core-сессии в resolver'е. */
|
||||
@@ -108,13 +109,16 @@ export class MarketplaceOrderCancelService {
|
||||
orderer: input.orderer_account,
|
||||
order_hash: order.order_hash,
|
||||
});
|
||||
txHash = this.normalizeTxHash(tx);
|
||||
txHash = normalizeChainTxHash(
|
||||
tx,
|
||||
'Отмена заказа: цепь не вернула tx_hash. Повторите попытку.'
|
||||
);
|
||||
} catch (error: any) {
|
||||
this.logger.error(
|
||||
`MarketplaceOrderCancelService: chain.cancelOrder fail для Order ${order.id} (orderer=${input.orderer_account}): ${error.message}`,
|
||||
error.stack
|
||||
);
|
||||
this.rethrowChainError(error);
|
||||
rethrowChainError(error);
|
||||
}
|
||||
|
||||
// ── 3. Counter onOrderUnblocked (best-effort) ───────────────────
|
||||
@@ -139,41 +143,6 @@ export class MarketplaceOrderCancelService {
|
||||
|
||||
return { order: updated, tx_hash: txHash! };
|
||||
}
|
||||
|
||||
private normalizeTxHash(tx: unknown): string {
|
||||
// wharfkit TransactResult держит Antelope push_transaction response под
|
||||
// `response` (response.processed.id / response.transaction_id). Для
|
||||
// совместимости со spec-тестами поддерживаем и плоский processed.id.
|
||||
const t = tx as {
|
||||
transaction?: { id?: string };
|
||||
processed?: { id?: string };
|
||||
response?: {
|
||||
transaction_id?: string;
|
||||
processed?: { id?: string };
|
||||
};
|
||||
};
|
||||
const hash =
|
||||
t?.response?.processed?.id ??
|
||||
t?.response?.transaction_id ??
|
||||
t?.processed?.id ??
|
||||
t?.transaction?.id;
|
||||
if (!hash) {
|
||||
// fail-fast: цепь приняла action, но не вернула tx_hash — audit-trail
|
||||
// станет фантомным ('unknown') без возможности cross-reference. Лучше
|
||||
// отбить отмену пайщику и попросить retry, чем записать «unknown».
|
||||
throw new BadRequestException(
|
||||
'Отмена заказа: цепь не вернула tx_hash. Повторите попытку.'
|
||||
);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
private rethrowChainError(error: any): never {
|
||||
const raw: string = error?.message ?? String(error);
|
||||
const match = raw.match(/assertion failure with message: (.+?)(?:\n|$)/);
|
||||
const clean = match ? match[1].trim() : raw;
|
||||
throw new BadRequestException(clean);
|
||||
}
|
||||
}
|
||||
|
||||
export const MARKETPLACE_ORDER_CANCEL_SERVICE = Symbol('MARKETPLACE_ORDER_CANCEL_SERVICE');
|
||||
|
||||
+2
-14
@@ -28,6 +28,7 @@ import {
|
||||
import type { MarketplaceOrderDomainEntity } from '../../domain/entities/marketplace-order.entity';
|
||||
import type { MarketplaceOrderCreateTxSnapshot } from '../../domain/entities/marketplace-order.types';
|
||||
import { toChainCycleType } from '../../domain/entities/marketplace-offer.types';
|
||||
import { rethrowChainError } from '../shared/chain-tx.util';
|
||||
|
||||
export interface MarketplaceOrderCreateInputDto {
|
||||
/** coopname кооператива. Берётся из core-сессии в resolver'е. */
|
||||
@@ -180,7 +181,7 @@ export class MarketplaceOrderCreateService {
|
||||
compErr.stack
|
||||
);
|
||||
}
|
||||
this.rethrowChainError(error);
|
||||
rethrowChainError(error);
|
||||
}
|
||||
|
||||
// ── 5. Persist PG row Order с tx snapshot ──────────────────────
|
||||
@@ -356,19 +357,6 @@ export class MarketplaceOrderCreateService {
|
||||
const block_num = t?.response?.processed?.block_num ?? 0;
|
||||
return { tx_hash, block_num };
|
||||
}
|
||||
|
||||
/**
|
||||
* Антелопе chain exception приходит в exception.message с трейсом и
|
||||
* `assertion failure with message: <текст>`. Эта функция вытаскивает
|
||||
* чистое сообщение и оборачивает в BadRequestException для clean
|
||||
* пользовательского ответа.
|
||||
*/
|
||||
private rethrowChainError(error: any): never {
|
||||
const raw: string = error?.message ?? String(error);
|
||||
const match = raw.match(/assertion failure with message: (.+?)(?:\n|$)/);
|
||||
const clean = match ? match[1].trim() : raw;
|
||||
throw new BadRequestException(clean);
|
||||
}
|
||||
}
|
||||
|
||||
export const MARKETPLACE_ORDER_CREATE_SERVICE = Symbol('MARKETPLACE_ORDER_CREATE_SERVICE');
|
||||
|
||||
+11
-39
@@ -26,6 +26,7 @@ import {
|
||||
MarketplaceOrderCycleTypes,
|
||||
MarketplaceOrderStatuses,
|
||||
} from '../../domain/entities/marketplace-order.types';
|
||||
import { normalizeChainTxHash, rethrowChainError } from '../shared/chain-tx.util';
|
||||
|
||||
export interface MarketplaceSupplierAcceptInput {
|
||||
coopname: string;
|
||||
@@ -83,13 +84,16 @@ export class MarketplaceOrderSupplierActionService {
|
||||
offerer: input.offerer_account,
|
||||
order_hash: order.order_hash,
|
||||
});
|
||||
txHash = this.normalizeTxHash(tx);
|
||||
txHash = normalizeChainTxHash(
|
||||
tx,
|
||||
'Действие поставщика: цепь не вернула tx_hash. Повторите попытку.'
|
||||
);
|
||||
} catch (error: any) {
|
||||
this.logger.error(
|
||||
`MarketplaceOrderSupplierActionService.acceptIndividual: chain.acceptOrder fail для Order ${order.id}: ${error.message}`,
|
||||
error.stack
|
||||
);
|
||||
this.rethrowChainError(error);
|
||||
rethrowChainError(error);
|
||||
}
|
||||
|
||||
const updated = await this.orderRepo.applyStatusTransition(
|
||||
@@ -221,13 +225,16 @@ export class MarketplaceOrderSupplierActionService {
|
||||
offerer: offerer_account,
|
||||
order_hash: order.order_hash,
|
||||
});
|
||||
txHash = this.normalizeTxHash(tx);
|
||||
txHash = normalizeChainTxHash(
|
||||
tx,
|
||||
'Действие поставщика: цепь не вернула tx_hash. Повторите попытку.'
|
||||
);
|
||||
} catch (error: any) {
|
||||
this.logger.error(
|
||||
`MarketplaceOrderSupplierActionService: chain.declineOrder fail для Order ${order.id}: ${error.message}`,
|
||||
error.stack
|
||||
);
|
||||
this.rethrowChainError(error);
|
||||
rethrowChainError(error);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -265,41 +272,6 @@ export class MarketplaceOrderSupplierActionService {
|
||||
}
|
||||
return order;
|
||||
}
|
||||
|
||||
private normalizeTxHash(tx: unknown): string {
|
||||
// wharfkit TransactResult держит Antelope push_transaction response под
|
||||
// `response` (response.processed.id / response.transaction_id). Для
|
||||
// совместимости со spec-тестами поддерживаем и плоский processed.id.
|
||||
const t = tx as {
|
||||
transaction?: { id?: string };
|
||||
processed?: { id?: string };
|
||||
response?: {
|
||||
transaction_id?: string;
|
||||
processed?: { id?: string };
|
||||
};
|
||||
};
|
||||
const hash =
|
||||
t?.response?.processed?.id ??
|
||||
t?.response?.transaction_id ??
|
||||
t?.processed?.id ??
|
||||
t?.transaction?.id;
|
||||
if (!hash) {
|
||||
// fail-fast: цепь приняла action, но не вернула tx_hash —
|
||||
// лучше отбить поставщику и попросить retry, чем записать
|
||||
// 'unknown' в audit-trail.
|
||||
throw new BadRequestException(
|
||||
'Действие поставщика: цепь не вернула tx_hash. Повторите попытку.'
|
||||
);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
private rethrowChainError(error: any): never {
|
||||
const raw: string = error?.message ?? String(error);
|
||||
const match = raw.match(/assertion failure with message: (.+?)(?:\n|$)/);
|
||||
const clean = match ? match[1].trim() : raw;
|
||||
throw new BadRequestException(clean);
|
||||
}
|
||||
}
|
||||
|
||||
export const MARKETPLACE_ORDER_SUPPLIER_ACTION_SERVICE = Symbol(
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
|
||||
/**
|
||||
* Извлекает tx_hash из ответа цепи (wharfkit TransactResult).
|
||||
*
|
||||
* wharfkit держит Antelope push_transaction response под `response`
|
||||
* (`response.processed.id` / `response.transaction_id`). Для совместимости
|
||||
* со spec-тестами поддерживаем и плоский `processed.id` / `transaction.id`.
|
||||
*
|
||||
* fail-fast: цепь приняла action, но не вернула tx_hash — audit-trail станет
|
||||
* фантомным ('unknown') без возможности cross-reference. Лучше отбить операцию
|
||||
* пайщику с просьбой о retry (`txHashMissingMessage`), чем записать «unknown».
|
||||
*/
|
||||
export function normalizeChainTxHash(tx: unknown, txHashMissingMessage: string): string {
|
||||
const t = tx as {
|
||||
transaction?: { id?: string };
|
||||
processed?: { id?: string };
|
||||
response?: {
|
||||
transaction_id?: string;
|
||||
processed?: { id?: string };
|
||||
};
|
||||
};
|
||||
const hash =
|
||||
t?.response?.processed?.id ??
|
||||
t?.response?.transaction_id ??
|
||||
t?.processed?.id ??
|
||||
t?.transaction?.id;
|
||||
if (!hash) {
|
||||
throw new BadRequestException(txHashMissingMessage);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Чистит `assertion failure with message: ...` из `eosio::check` и пробрасывает
|
||||
* пайщику как BadRequest с человекочитаемым текстом (без EOSIO-обёртки).
|
||||
*/
|
||||
export function rethrowChainError(error: unknown): never {
|
||||
const raw: string = (error as { message?: string })?.message ?? String(error);
|
||||
const match = raw.match(/assertion failure with message: (.+?)(?:\n|$)/);
|
||||
const clean = match ? match[1].trim() : raw;
|
||||
throw new BadRequestException(clean);
|
||||
}
|
||||
+7
-7
@@ -30,11 +30,11 @@ const makeResolver = (reception: any, isMember: boolean) => {
|
||||
findById: jest.fn().mockResolvedValue(reception),
|
||||
listByBraname: jest.fn().mockResolvedValue([]),
|
||||
} as any;
|
||||
const kuChairmenService = {
|
||||
const kuChairmanService = {
|
||||
isMemberOfBranch: jest.fn().mockResolvedValue(isMember),
|
||||
} as any;
|
||||
const resolver = new MarketplaceAplReceptionResolver(service, receptionRepo, kuChairmenService);
|
||||
return { resolver, service, receptionRepo, kuChairmenService };
|
||||
const resolver = new MarketplaceAplReceptionResolver(service, receptionRepo, kuChairmanService);
|
||||
return { resolver, service, receptionRepo, kuChairmanService };
|
||||
};
|
||||
|
||||
const asMember = (roles: string[]) =>
|
||||
@@ -42,11 +42,11 @@ const asMember = (roles: string[]) =>
|
||||
|
||||
describe('marketplaceListAplReceptionsByBraname ownership-scoping', () => {
|
||||
it('operator-член запрашиваемого КУ → лента отдаётся', async () => {
|
||||
const { resolver, receptionRepo, kuChairmenService } = makeResolver(receptionOf({}), true);
|
||||
const { resolver, receptionRepo, kuChairmanService } = makeResolver(receptionOf({}), true);
|
||||
await resolver.marketplaceListAplReceptionsByBraname(asMember(['operator']), {
|
||||
braname: 'krg',
|
||||
} as any);
|
||||
expect(kuChairmenService.isMemberOfBranch).toHaveBeenCalledWith('voskhod', 'krg', 'op');
|
||||
expect(kuChairmanService.isMemberOfBranch).toHaveBeenCalledWith('voskhod', 'krg', 'op');
|
||||
expect(receptionRepo.listByBraname).toHaveBeenCalledWith('voskhod', 'krg');
|
||||
});
|
||||
|
||||
@@ -83,11 +83,11 @@ describe('marketplaceAplReceptionSupplierSignablePayloads ownership-scoping', ()
|
||||
|
||||
describe('marketplaceAplReceptionChairmanSignablePayloads ownership-scoping', () => {
|
||||
it('operator-член КУ приёмки → превью отдаётся', async () => {
|
||||
const { resolver, service, kuChairmenService } = makeResolver(receptionOf({}), true);
|
||||
const { resolver, service, kuChairmanService } = makeResolver(receptionOf({}), true);
|
||||
await resolver.marketplaceAplReceptionChairmanSignablePayloads(asMember(['operator']), {
|
||||
apl_reception_id: 'r1',
|
||||
} as any);
|
||||
expect(kuChairmenService.isMemberOfBranch).toHaveBeenCalledWith('voskhod', 'krg', 'op');
|
||||
expect(kuChairmanService.isMemberOfBranch).toHaveBeenCalledWith('voskhod', 'krg', 'op');
|
||||
expect(service.getChairmanSignablePayloads).toHaveBeenCalledWith('voskhod', 'r1', 'op');
|
||||
});
|
||||
|
||||
|
||||
+7
-7
@@ -21,15 +21,15 @@ import { MarketplaceInventoryResolver } from '~/extensions/marketplace/applicati
|
||||
const makeResolver = (ownBranames: string[]) => {
|
||||
const inventoryRepo = { list: jest.fn().mockResolvedValue([]) } as any;
|
||||
const labelService = {} as any;
|
||||
const kuChairmenService = {
|
||||
const kuChairmanService = {
|
||||
listBranamesForMember: jest.fn().mockResolvedValue(ownBranames),
|
||||
} as any;
|
||||
const resolver = new MarketplaceInventoryResolver(
|
||||
labelService,
|
||||
inventoryRepo,
|
||||
kuChairmenService
|
||||
kuChairmanService
|
||||
);
|
||||
return { resolver, inventoryRepo, kuChairmenService };
|
||||
return { resolver, inventoryRepo, kuChairmanService };
|
||||
};
|
||||
|
||||
const asMember = (roles: string[]) =>
|
||||
@@ -37,20 +37,20 @@ const asMember = (roles: string[]) =>
|
||||
|
||||
describe('marketplaceListInventory ownership-scoping', () => {
|
||||
it('admin (read:all) без braname → НЕ скоупит, braname=undefined, КУ-сервис не дёргается', async () => {
|
||||
const { resolver, inventoryRepo, kuChairmenService } = makeResolver(['krg']);
|
||||
const { resolver, inventoryRepo, kuChairmanService } = makeResolver(['krg']);
|
||||
await resolver.marketplaceListInventory(asMember(['admin']), undefined);
|
||||
expect(kuChairmenService.listBranamesForMember).not.toHaveBeenCalled();
|
||||
expect(kuChairmanService.listBranamesForMember).not.toHaveBeenCalled();
|
||||
expect(inventoryRepo.list).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ coopname: 'voskhod', braname: undefined })
|
||||
);
|
||||
});
|
||||
|
||||
it('board_readonly (read:all) с braname → braname как пришёл, без скоупа', async () => {
|
||||
const { resolver, inventoryRepo, kuChairmenService } = makeResolver(['krg']);
|
||||
const { resolver, inventoryRepo, kuChairmanService } = makeResolver(['krg']);
|
||||
await resolver.marketplaceListInventory(asMember(['board_readonly']), {
|
||||
braname: 'krg',
|
||||
} as any);
|
||||
expect(kuChairmenService.listBranamesForMember).not.toHaveBeenCalled();
|
||||
expect(kuChairmanService.listBranamesForMember).not.toHaveBeenCalled();
|
||||
expect(inventoryRepo.list).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ braname: 'krg' })
|
||||
);
|
||||
|
||||
+10
-10
@@ -19,11 +19,11 @@ import { MarketplaceIssuanceResolver } from '~/extensions/marketplace/applicatio
|
||||
const makeResolver = (isMember: boolean) => {
|
||||
const service = {} as any;
|
||||
const orderRepo = { listForIssuanceByBraname: jest.fn().mockResolvedValue([]) } as any;
|
||||
const kuChairmenService = {
|
||||
const kuChairmanService = {
|
||||
isMemberOfBranch: jest.fn().mockResolvedValue(isMember),
|
||||
} as any;
|
||||
const resolver = new MarketplaceIssuanceResolver(service, orderRepo, kuChairmenService);
|
||||
return { resolver, orderRepo, kuChairmenService };
|
||||
const resolver = new MarketplaceIssuanceResolver(service, orderRepo, kuChairmanService);
|
||||
return { resolver, orderRepo, kuChairmanService };
|
||||
};
|
||||
|
||||
const asMember = (roles: string[]) =>
|
||||
@@ -31,11 +31,11 @@ const asMember = (roles: string[]) =>
|
||||
|
||||
describe('marketplaceListIssuancesByBraname ownership-scoping', () => {
|
||||
it('operator-член запрашиваемого КУ → лента отдаётся', async () => {
|
||||
const { resolver, orderRepo, kuChairmenService } = makeResolver(true);
|
||||
const { resolver, orderRepo, kuChairmanService } = makeResolver(true);
|
||||
await resolver.marketplaceListIssuancesByBraname(asMember(['operator']), {
|
||||
delivery_braname: 'krg',
|
||||
} as any);
|
||||
expect(kuChairmenService.isMemberOfBranch).toHaveBeenCalledWith('voskhod', 'krg', 'op');
|
||||
expect(kuChairmanService.isMemberOfBranch).toHaveBeenCalledWith('voskhod', 'krg', 'op');
|
||||
expect(orderRepo.listForIssuanceByBraname).toHaveBeenCalledWith('voskhod', 'krg');
|
||||
});
|
||||
|
||||
@@ -68,18 +68,18 @@ const makePayloadResolver = (order: any, isMember: boolean) => {
|
||||
}),
|
||||
} as any;
|
||||
const orderRepo = { findById: jest.fn().mockResolvedValue(order) } as any;
|
||||
const kuChairmenService = { isMemberOfBranch: jest.fn().mockResolvedValue(isMember) } as any;
|
||||
const resolver = new MarketplaceIssuanceResolver(service, orderRepo, kuChairmenService);
|
||||
return { resolver, service, orderRepo, kuChairmenService };
|
||||
const kuChairmanService = { isMemberOfBranch: jest.fn().mockResolvedValue(isMember) } as any;
|
||||
const resolver = new MarketplaceIssuanceResolver(service, orderRepo, kuChairmanService);
|
||||
return { resolver, service, orderRepo, kuChairmanService };
|
||||
};
|
||||
|
||||
describe('marketplaceIssueActChairmanSignablePayload ownership-scoping', () => {
|
||||
it('operator-член КУ заказа → превью отдаётся', async () => {
|
||||
const { resolver, service, kuChairmenService } = makePayloadResolver(orderOf({}), true);
|
||||
const { resolver, service, kuChairmanService } = makePayloadResolver(orderOf({}), true);
|
||||
await resolver.marketplaceIssueActChairmanSignablePayload(asMember(['operator']), {
|
||||
order_id: 'o1',
|
||||
} as any);
|
||||
expect(kuChairmenService.isMemberOfBranch).toHaveBeenCalledWith('voskhod', 'krg', 'op');
|
||||
expect(kuChairmanService.isMemberOfBranch).toHaveBeenCalledWith('voskhod', 'krg', 'op');
|
||||
expect(service.getOpenIssuanceSignablePayload).toHaveBeenCalledWith('voskhod', 'o1', 'op');
|
||||
});
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
import { ForbiddenException, UnauthorizedException } from '@nestjs/common';
|
||||
|
||||
import { MarketplaceMembershipGuard } from '~/extensions/marketplace/application/guards/marketplace-membership.guard';
|
||||
import type { MarketplaceKuChairmenService } from '~/extensions/marketplace/application/services/marketplace-ku-chairmen.service';
|
||||
import type { MarketplaceKuChairmanService } from '~/extensions/marketplace/application/services/marketplace-ku-chairman.service';
|
||||
import type { MarketplaceWhitelistService } from '~/extensions/marketplace/application/services/marketplace-whitelist.service';
|
||||
|
||||
jest.mock('~/config/config', () => ({
|
||||
@@ -48,15 +48,15 @@ function makeWhitelistService(isOffererResult: boolean): MarketplaceWhitelistSer
|
||||
} as unknown as MarketplaceWhitelistService;
|
||||
}
|
||||
|
||||
function makeKuChairmenService(isKuChairmanResult: boolean): MarketplaceKuChairmenService {
|
||||
function makeKuChairmanService(isKuChairmanResult: boolean): MarketplaceKuChairmanService {
|
||||
return {
|
||||
isKuChairman: jest.fn().mockResolvedValue(isKuChairmanResult),
|
||||
} as unknown as MarketplaceKuChairmenService;
|
||||
} as unknown as MarketplaceKuChairmanService;
|
||||
}
|
||||
|
||||
describe('MarketplaceMembershipGuard', () => {
|
||||
it('user.role=user, status=active, whitelist пуст → ctx [User] + marketplace_roles [orderer, offerer]', async () => {
|
||||
const guard = new MarketplaceMembershipGuard(makeWhitelistService(true), makeKuChairmenService(false));
|
||||
const guard = new MarketplaceMembershipGuard(makeWhitelistService(true), makeKuChairmanService(false));
|
||||
const req = { user: { username: 'alice', role: 'user', status: 'active' }, headers: {} };
|
||||
const ctx = makeCtx(req);
|
||||
|
||||
@@ -70,7 +70,7 @@ describe('MarketplaceMembershipGuard', () => {
|
||||
});
|
||||
|
||||
it('user.role=user, whitelist непустой и пайщика там нет → marketplace_roles [orderer] (без offerer)', async () => {
|
||||
const guard = new MarketplaceMembershipGuard(makeWhitelistService(false), makeKuChairmenService(false));
|
||||
const guard = new MarketplaceMembershipGuard(makeWhitelistService(false), makeKuChairmanService(false));
|
||||
const req = { user: { username: 'alice', role: 'user', status: 'active' }, headers: {} };
|
||||
const ctx = makeCtx(req);
|
||||
|
||||
@@ -79,7 +79,7 @@ describe('MarketplaceMembershipGuard', () => {
|
||||
});
|
||||
|
||||
it('user.role=member, status=active → core_roles [User, Member] + marketplace_roles [orderer, offerer, board_readonly]', async () => {
|
||||
const guard = new MarketplaceMembershipGuard(makeWhitelistService(true), makeKuChairmenService(false));
|
||||
const guard = new MarketplaceMembershipGuard(makeWhitelistService(true), makeKuChairmanService(false));
|
||||
const req = { user: { username: 'bob', role: 'member', status: 'active' }, headers: {} };
|
||||
const ctx = makeCtx(req);
|
||||
await expect(guard.canActivate(ctx as any)).resolves.toBe(true);
|
||||
@@ -92,7 +92,7 @@ describe('MarketplaceMembershipGuard', () => {
|
||||
});
|
||||
|
||||
it('user.role=chairman, status=active → marketplace_roles полный набор', async () => {
|
||||
const guard = new MarketplaceMembershipGuard(makeWhitelistService(true), makeKuChairmenService(false));
|
||||
const guard = new MarketplaceMembershipGuard(makeWhitelistService(true), makeKuChairmanService(false));
|
||||
const req = { user: { username: 'chair', role: 'chairman', status: 'active' }, headers: {} };
|
||||
const ctx = makeCtx(req);
|
||||
await expect(guard.canActivate(ctx as any)).resolves.toBe(true);
|
||||
@@ -107,7 +107,7 @@ describe('MarketplaceMembershipGuard', () => {
|
||||
});
|
||||
|
||||
it('status != active → 403 Forbidden «Доступ только для пайщиков кооператива»', async () => {
|
||||
const guard = new MarketplaceMembershipGuard(makeWhitelistService(false), makeKuChairmenService(false));
|
||||
const guard = new MarketplaceMembershipGuard(makeWhitelistService(false), makeKuChairmanService(false));
|
||||
const req = { user: { username: 'alice', role: 'user', status: '4_Registered' }, headers: {} };
|
||||
const ctx = makeCtx(req);
|
||||
await expect(guard.canActivate(ctx as any)).rejects.toThrow(ForbiddenException);
|
||||
@@ -117,7 +117,7 @@ describe('MarketplaceMembershipGuard', () => {
|
||||
});
|
||||
|
||||
it('нет user (нет JWT) → 401 Unauthorized', async () => {
|
||||
const guard = new MarketplaceMembershipGuard(makeWhitelistService(false), makeKuChairmenService(false));
|
||||
const guard = new MarketplaceMembershipGuard(makeWhitelistService(false), makeKuChairmanService(false));
|
||||
const req = { headers: {} };
|
||||
const ctx = makeCtx(req);
|
||||
await expect(guard.canActivate(ctx as any)).rejects.toThrow(UnauthorizedException);
|
||||
@@ -125,7 +125,7 @@ describe('MarketplaceMembershipGuard', () => {
|
||||
|
||||
it('server-secret bypass → true, currentMember не выставляется, whitelist/branches не дёргаются', async () => {
|
||||
const ws = makeWhitelistService(true);
|
||||
const ku = makeKuChairmenService(false);
|
||||
const ku = makeKuChairmanService(false);
|
||||
const guard = new MarketplaceMembershipGuard(ws, ku);
|
||||
const req = { headers: { 'server-secret': 'test-secret' } };
|
||||
const ctx = makeCtx(req);
|
||||
@@ -136,7 +136,7 @@ describe('MarketplaceMembershipGuard', () => {
|
||||
});
|
||||
|
||||
it('isKuChairman=true → marketplace_roles содержит operator', async () => {
|
||||
const guard = new MarketplaceMembershipGuard(makeWhitelistService(false), makeKuChairmenService(true));
|
||||
const guard = new MarketplaceMembershipGuard(makeWhitelistService(false), makeKuChairmanService(true));
|
||||
const req = { user: { username: 'chairkrg', role: 'user', status: 'active' }, headers: {} };
|
||||
const ctx = makeCtx(req);
|
||||
await expect(guard.canActivate(ctx as any)).resolves.toBe(true);
|
||||
|
||||
@@ -754,6 +754,12 @@ export const AllTypesProps: Record<string,any> = {
|
||||
MarketplaceListOrdersInput:{
|
||||
statuses:"MarketplaceOrderStatus"
|
||||
},
|
||||
MarketplaceListOutgoingPaymentsAsSupplierFilterInput:{
|
||||
statuses:"MarketplaceOutgoingPaymentRequestStatus"
|
||||
},
|
||||
MarketplaceListOutgoingPaymentsFilterInput:{
|
||||
statuses:"MarketplaceOutgoingPaymentRequestStatus"
|
||||
},
|
||||
MarketplaceListPendingOffersInput:{
|
||||
|
||||
},
|
||||
@@ -1980,10 +1986,10 @@ export const AllTypesProps: Record<string,any> = {
|
||||
options:"PaginationInput"
|
||||
},
|
||||
marketplaceListOutgoingPayments:{
|
||||
statuses:"MarketplaceOutgoingPaymentRequestStatus"
|
||||
filter:"MarketplaceListOutgoingPaymentsFilterInput"
|
||||
},
|
||||
marketplaceListOutgoingPaymentsAsSupplier:{
|
||||
statuses:"MarketplaceOutgoingPaymentRequestStatus"
|
||||
filter:"MarketplaceListOutgoingPaymentsAsSupplierFilterInput"
|
||||
},
|
||||
marketplaceListPendingOffers:{
|
||||
input:"MarketplaceListPendingOffersInput"
|
||||
|
||||
@@ -6866,6 +6866,16 @@ export type ValueTypes = {
|
||||
statuses?: Array<ValueTypes["MarketplaceOrderStatus"]> | undefined | null | Variable<any, string>,
|
||||
/** Фильтр по аккаунту поставщика. */
|
||||
supplier_account?: string | undefined | null | Variable<any, string>
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<ValueTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null | Variable<any, string>
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<ValueTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null | Variable<any, string>,
|
||||
/** Поставщик-получатель выплаты. Пусто — по всем поставщикам. */
|
||||
supplier_account?: string | undefined | null | Variable<any, string>
|
||||
};
|
||||
["MarketplaceListPendingOffersInput"]: {
|
||||
/** Количество элементов на странице */
|
||||
@@ -9594,8 +9604,8 @@ marketplaceListMyOrders?: [{ input?: ValueTypes["MarketplaceListOrdersInput"] |
|
||||
marketplaceListMyReadyToReceive?:ValueTypes["MarketplaceOrder"],
|
||||
/** Все заявления текущего пайщика на гарантийный возврат — активные и архивные. */
|
||||
marketplaceListMyReturnClaims?:ValueTypes["MarketplaceReturnClaim"],
|
||||
marketplaceListOutgoingPayments?: [{ statuses?: Array<ValueTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null | Variable<any, string>, supplier_account?: string | undefined | null | Variable<any, string>},ValueTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListOutgoingPaymentsAsSupplier?: [{ statuses?: Array<ValueTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null | Variable<any, string>},ValueTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListOutgoingPayments?: [{ filter?: ValueTypes["MarketplaceListOutgoingPaymentsFilterInput"] | undefined | null | Variable<any, string>},ValueTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListOutgoingPaymentsAsSupplier?: [{ filter?: ValueTypes["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"] | undefined | null | Variable<any, string>},ValueTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListPendingOffers?: [{ input?: ValueTypes["MarketplaceListPendingOffersInput"] | undefined | null | Variable<any, string>},ValueTypes["MarketplaceOfferPaginationResult"]],
|
||||
marketplaceListReturnClaimsByBraname?: [{ data: ValueTypes["MarketplaceListReturnClaimsByBranameInput"] | Variable<any, string>},ValueTypes["MarketplaceReturnClaim"]],
|
||||
marketplaceListShipments?: [{ data?: ValueTypes["MarketplaceListShipmentsInput"] | undefined | null | Variable<any, string>},ValueTypes["MarketplaceShipment"]],
|
||||
@@ -16818,6 +16828,16 @@ export type ResolverInputTypes = {
|
||||
statuses?: Array<ResolverInputTypes["MarketplaceOrderStatus"]> | undefined | null,
|
||||
/** Фильтр по аккаунту поставщика. */
|
||||
supplier_account?: string | undefined | null
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<ResolverInputTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<ResolverInputTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null,
|
||||
/** Поставщик-получатель выплаты. Пусто — по всем поставщикам. */
|
||||
supplier_account?: string | undefined | null
|
||||
};
|
||||
["MarketplaceListPendingOffersInput"]: {
|
||||
/** Количество элементов на странице */
|
||||
@@ -19449,8 +19469,8 @@ marketplaceListMyOrders?: [{ input?: ResolverInputTypes["MarketplaceListOrdersIn
|
||||
marketplaceListMyReadyToReceive?:ResolverInputTypes["MarketplaceOrder"],
|
||||
/** Все заявления текущего пайщика на гарантийный возврат — активные и архивные. */
|
||||
marketplaceListMyReturnClaims?:ResolverInputTypes["MarketplaceReturnClaim"],
|
||||
marketplaceListOutgoingPayments?: [{ statuses?: Array<ResolverInputTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null, supplier_account?: string | undefined | null},ResolverInputTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListOutgoingPaymentsAsSupplier?: [{ statuses?: Array<ResolverInputTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null},ResolverInputTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListOutgoingPayments?: [{ filter?: ResolverInputTypes["MarketplaceListOutgoingPaymentsFilterInput"] | undefined | null},ResolverInputTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListOutgoingPaymentsAsSupplier?: [{ filter?: ResolverInputTypes["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"] | undefined | null},ResolverInputTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListPendingOffers?: [{ input?: ResolverInputTypes["MarketplaceListPendingOffersInput"] | undefined | null},ResolverInputTypes["MarketplaceOfferPaginationResult"]],
|
||||
marketplaceListReturnClaimsByBraname?: [{ data: ResolverInputTypes["MarketplaceListReturnClaimsByBranameInput"]},ResolverInputTypes["MarketplaceReturnClaim"]],
|
||||
marketplaceListShipments?: [{ data?: ResolverInputTypes["MarketplaceListShipmentsInput"] | undefined | null},ResolverInputTypes["MarketplaceShipment"]],
|
||||
@@ -26449,6 +26469,16 @@ export type ModelTypes = {
|
||||
statuses?: Array<ModelTypes["MarketplaceOrderStatus"]> | undefined | null,
|
||||
/** Фильтр по аккаунту поставщика. */
|
||||
supplier_account?: string | undefined | null
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<ModelTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<ModelTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null,
|
||||
/** Поставщик-получатель выплаты. Пусто — по всем поставщикам. */
|
||||
supplier_account?: string | undefined | null
|
||||
};
|
||||
["MarketplaceListPendingOffersInput"]: {
|
||||
/** Количество элементов на странице */
|
||||
@@ -36996,6 +37026,16 @@ export type GraphQLTypes = {
|
||||
statuses?: Array<GraphQLTypes["MarketplaceOrderStatus"]> | undefined | null,
|
||||
/** Фильтр по аккаунту поставщика. */
|
||||
supplier_account?: string | undefined | null
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<GraphQLTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<GraphQLTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null,
|
||||
/** Поставщик-получатель выплаты. Пусто — по всем поставщикам. */
|
||||
supplier_account?: string | undefined | null
|
||||
};
|
||||
["MarketplaceListPendingOffersInput"]: {
|
||||
/** Количество элементов на странице */
|
||||
@@ -42933,6 +42973,8 @@ type ZEUS_VARIABLES = {
|
||||
["MarketplaceListIssuancesByBranameInput"]: ValueTypes["MarketplaceListIssuancesByBranameInput"];
|
||||
["MarketplaceListMyOffersInput"]: ValueTypes["MarketplaceListMyOffersInput"];
|
||||
["MarketplaceListOrdersInput"]: ValueTypes["MarketplaceListOrdersInput"];
|
||||
["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"]: ValueTypes["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"];
|
||||
["MarketplaceListOutgoingPaymentsFilterInput"]: ValueTypes["MarketplaceListOutgoingPaymentsFilterInput"];
|
||||
["MarketplaceListPendingOffersInput"]: ValueTypes["MarketplaceListPendingOffersInput"];
|
||||
["MarketplaceListReturnClaimsByBranameInput"]: ValueTypes["MarketplaceListReturnClaimsByBranameInput"];
|
||||
["MarketplaceListShipmentsByBranameInput"]: ValueTypes["MarketplaceListShipmentsByBranameInput"];
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import * as Permissions from '../../../common/permissions'
|
||||
import type * as Wallet from '../../../interfaces/wallet'
|
||||
import { Actors } from '../../../common'
|
||||
|
||||
/**
|
||||
* Имя действия
|
||||
* Требуется авторизация {@link Actors._chairman | председателя} — авторизацию
|
||||
* выплаты по заявке на возврат паевого взноса выполняет совет.
|
||||
*/
|
||||
export const authorizations = [{ permissions: [Permissions.active], actor: Actors._chairman }] as const
|
||||
|
||||
/**
|
||||
* Имя действия
|
||||
*/
|
||||
export const actionName = 'authwthd'
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* Действие авторизации советом выплаты по заявке на возврат паевого взноса
|
||||
* из кошелька (переводит заявку в статус, видимый кассиру).
|
||||
*/
|
||||
export type IAuthWithdraw = Wallet.IAuthwthd
|
||||
@@ -0,0 +1,22 @@
|
||||
import * as Permissions from '../../../common/permissions'
|
||||
import type * as Wallet from '../../../interfaces/wallet'
|
||||
import { Actors } from '../../../common'
|
||||
|
||||
/**
|
||||
* Имя действия
|
||||
* Требуется авторизация {@link Actors._chairman | председателя} — отказ в
|
||||
* выплате по заявке на возврат паевого взноса выполняет совет.
|
||||
*/
|
||||
export const authorizations = [{ permissions: [Permissions.active], actor: Actors._chairman }] as const
|
||||
|
||||
/**
|
||||
* Имя действия
|
||||
*/
|
||||
export const actionName = 'declinewthd'
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* Действие отказа советом в выплате по заявке на возврат паевого взноса
|
||||
* из кошелька (переводит заявку в статус «отклонено»).
|
||||
*/
|
||||
export type IDeclineWithdraw = Wallet.IDeclinewthd
|
||||
@@ -2,6 +2,9 @@ export * as CreateDeposit from './createDeposit'
|
||||
|
||||
export * as CreateWithdraw from './createWithdraw'
|
||||
|
||||
export * as AuthWithdraw from './authWithdraw'
|
||||
export * as DeclineWithdraw from './declineWithdraw'
|
||||
|
||||
export * as SignAgreement from './signAgreement'
|
||||
export * as RevokeAgreement from './revokeAgreement'
|
||||
export * as Migrate3 from './migrate3'
|
||||
|
||||
@@ -427,7 +427,7 @@ export default async function (): Promise<IWorkspaceConfig[]> {
|
||||
// Стол ПВЗ открыт двум профилям пайщиков:
|
||||
// - cooperative chairman (core-роль `chairman`) — видит все КУ;
|
||||
// - председатель КУ или его доверенное лицо (marketplace-роль
|
||||
// `operator`, выдаётся через `MarketplaceKuChairmenService`).
|
||||
// `operator`, выдаётся через `MarketplaceKuChairmanService`).
|
||||
// OR-логика подключается router-guard'ом при наличии обоих
|
||||
// ограничений (см. processes/navigation-guard-setup).
|
||||
meta: {
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { Queries } from '@coopenomics/sdk';
|
||||
import { client } from 'src/shared/api/client';
|
||||
|
||||
export interface MarketplaceCurrentMemberView {
|
||||
username: string;
|
||||
core_roles: string[];
|
||||
marketplace_roles: string[];
|
||||
branches: string[];
|
||||
}
|
||||
export type MarketplaceCurrentMemberView =
|
||||
Queries.Marketplace.WhoAmI.IOutput['marketplaceWhoAmI'];
|
||||
|
||||
export async function fetchWhoAmI(): Promise<MarketplaceCurrentMemberView> {
|
||||
const result = await client.Query(Queries.Marketplace.WhoAmI.query, { variables: {} });
|
||||
return result[Queries.Marketplace.WhoAmI.name] as unknown as MarketplaceCurrentMemberView;
|
||||
const { [Queries.Marketplace.WhoAmI.name]: result } = await client.Query(
|
||||
Queries.Marketplace.WhoAmI.query,
|
||||
{ variables: {} },
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ import type { MarketplaceReturnClaimView } from '../../OperatorReturnClaims/api'
|
||||
*
|
||||
* Поле braname автозаполняется из `marketplaceWhoAmI.branches` — список КУ,
|
||||
* где пайщик доверенное лицо (on-chain branch.trustee/trusted через
|
||||
* MarketplaceKuChairmenService.listBranamesForMember). Один участок —
|
||||
* MarketplaceKuChairmanService.listBranamesForMember). Один участок —
|
||||
* подставляется сразу; несколько — берётся первый, поле остаётся редактируемым
|
||||
* для ручного переключения.
|
||||
*/
|
||||
|
||||
+4
-25
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { Notify } from 'quasar';
|
||||
import { FailAlert, SuccessAlert } from 'src/shared/api';
|
||||
import { useSystemStore } from 'src/entities/System/model';
|
||||
import { fetchBranchOptions, submitCreateOrder } from '../api';
|
||||
import type { BranchOption, MarketplaceOfferView } from '../types';
|
||||
@@ -81,8 +81,7 @@ watch(
|
||||
branch.value = branches.value[0]!.braname;
|
||||
}
|
||||
} catch (e) {
|
||||
const message = e instanceof Error ? e.message : String(e);
|
||||
Notify.create({ type: 'negative', message: `Не удалось загрузить ПВЗ: ${message}` });
|
||||
FailAlert(e, 'Не удалось загрузить ПВЗ');
|
||||
} finally {
|
||||
loadingBranches.value = false;
|
||||
}
|
||||
@@ -92,26 +91,6 @@ watch(
|
||||
},
|
||||
);
|
||||
|
||||
function extractErrorMessage(e: unknown): string {
|
||||
if (e instanceof Error && e.message) return e.message;
|
||||
if (Array.isArray(e) && e.length > 0) return extractErrorMessage(e[0]);
|
||||
if (e && typeof e === 'object') {
|
||||
const err = e as Record<string, unknown>;
|
||||
if (typeof err.message === 'string') return err.message;
|
||||
const gql = err.graphQLErrors;
|
||||
if (Array.isArray(gql) && gql.length > 0) return extractErrorMessage(gql[0]);
|
||||
const resp = err.response as Record<string, unknown> | undefined;
|
||||
if (resp && Array.isArray(resp.errors) && resp.errors.length > 0) {
|
||||
return extractErrorMessage(resp.errors[0]);
|
||||
}
|
||||
}
|
||||
try {
|
||||
return JSON.stringify(e);
|
||||
} catch {
|
||||
return String(e);
|
||||
}
|
||||
}
|
||||
|
||||
async function onSubmit(): Promise<void> {
|
||||
if (!props.offer || !branch.value) return;
|
||||
submitting.value = true;
|
||||
@@ -121,11 +100,11 @@ async function onSubmit(): Promise<void> {
|
||||
quantity: Number(quantity.value),
|
||||
delivery_braname: branch.value,
|
||||
});
|
||||
Notify.create({ type: 'positive', message: 'Заказ создан' });
|
||||
SuccessAlert('Заказ создан');
|
||||
emit('created');
|
||||
open.value = false;
|
||||
} catch (e) {
|
||||
Notify.create({ type: 'negative', message: extractErrorMessage(e) });
|
||||
FailAlert(e);
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
}
|
||||
|
||||
@@ -14,39 +14,43 @@ export interface ListMyOrdersVariables {
|
||||
|
||||
export async function fetchMyOrders(variables: ListMyOrdersVariables = {}): Promise<MarketplaceOrderPage> {
|
||||
const { page, limit, sortBy, sortOrder, statuses, supplier_account, offer_id } = variables;
|
||||
const result = await client.Query(Queries.Marketplace.ListMyOrders.query, {
|
||||
variables: {
|
||||
input: {
|
||||
supplier_account,
|
||||
offer_id,
|
||||
statuses,
|
||||
},
|
||||
options: {
|
||||
page: page ?? 1,
|
||||
limit: limit ?? 50,
|
||||
sortBy: sortBy ?? 'updated_at',
|
||||
sortOrder: sortOrder ?? 'DESC',
|
||||
const { [Queries.Marketplace.ListMyOrders.name]: result } = await client.Query(
|
||||
Queries.Marketplace.ListMyOrders.query,
|
||||
{
|
||||
variables: {
|
||||
input: {
|
||||
supplier_account,
|
||||
offer_id,
|
||||
statuses,
|
||||
},
|
||||
options: {
|
||||
page: page ?? 1,
|
||||
limit: limit ?? 50,
|
||||
sortBy: sortBy ?? 'updated_at',
|
||||
sortOrder: sortOrder ?? 'DESC',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
return result[Queries.Marketplace.ListMyOrders.name] as unknown as MarketplaceOrderPage;
|
||||
);
|
||||
// Zeus отдаёт DateTime как unknown; сужаем скалярную дату до строки во view-типе.
|
||||
return result as MarketplaceOrderPage;
|
||||
}
|
||||
|
||||
export async function fetchOrder(order_id: string): Promise<MarketplaceOrderView> {
|
||||
const result = await client.Query(Queries.Marketplace.GetOrder.query, {
|
||||
variables: { input: { order_id } },
|
||||
});
|
||||
return result[Queries.Marketplace.GetOrder.name] as unknown as MarketplaceOrderView;
|
||||
const { [Queries.Marketplace.GetOrder.name]: result } = await client.Query(
|
||||
Queries.Marketplace.GetOrder.query,
|
||||
{ variables: { input: { order_id } } },
|
||||
);
|
||||
return result as MarketplaceOrderView;
|
||||
}
|
||||
|
||||
export interface CancelOrderResult {
|
||||
order: MarketplaceOrderView;
|
||||
tx_hash: string;
|
||||
}
|
||||
export type CancelOrderResult =
|
||||
Mutations.Marketplace.CancelOrder.IOutput['marketplaceCancelOrder'];
|
||||
|
||||
export async function cancelOrder(order_id: string): Promise<CancelOrderResult> {
|
||||
const result = await client.Mutation(Mutations.Marketplace.CancelOrder.mutation, {
|
||||
variables: { input: { order_id } },
|
||||
});
|
||||
return result[Mutations.Marketplace.CancelOrder.name] as unknown as CancelOrderResult;
|
||||
const { [Mutations.Marketplace.CancelOrder.name]: result } = await client.Mutation(
|
||||
Mutations.Marketplace.CancelOrder.mutation,
|
||||
{ variables: { input: { order_id } } },
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,58 +1,33 @@
|
||||
/**
|
||||
* Story 4.6: типы orderer-стола «Мои заказы».
|
||||
* Источник истины — backend MarketplaceOrderDTO / Story 4.1/4.4 mutations.
|
||||
* Ручная типизация — техдолг до регенерации Zeus в `@coopenomics/sdk`.
|
||||
* Источник истины — Zeus-вывод операции marketplaceListMyOrders из @coopenomics/sdk.
|
||||
*/
|
||||
export type MarketplaceOrderStatusView =
|
||||
| 'ACTIVE'
|
||||
| 'ACCEPTED_PENDING_SUPPLIER'
|
||||
| 'ACCEPTED_PENDING_SUPPLIER_INDIVIDUAL'
|
||||
| 'ACCEPTED'
|
||||
| 'SUPPLY_PREPARED'
|
||||
| 'ACCEPTED_TO_COOP'
|
||||
| 'READY_TO_RECEIVE'
|
||||
| 'RECEIVED'
|
||||
| 'RETURNED'
|
||||
| 'CANCELLED_BY_ORDERER'
|
||||
| 'CANCELLED_BY_SUPPLIER'
|
||||
| 'EXPIRED_NO_THRESHOLD'
|
||||
| 'EXPIRED_NO_VOLUME';
|
||||
import { Queries } from '@coopenomics/sdk';
|
||||
|
||||
export type MarketplaceOrderCycleTypeView =
|
||||
| 'time_based'
|
||||
| 'volume_based'
|
||||
| 'open_subscription'
|
||||
| 'individual';
|
||||
type _RawOrderPage =
|
||||
Queries.Marketplace.ListMyOrders.IOutput['marketplaceListMyOrders'];
|
||||
|
||||
export interface MarketplaceOrderView {
|
||||
id: string;
|
||||
coopname: string;
|
||||
order_hash: string;
|
||||
orderer_account: string;
|
||||
offer_id: string;
|
||||
offer_hash: string;
|
||||
supplier_account: string;
|
||||
delivery_braname: string;
|
||||
quantity: number;
|
||||
price_per_unit: string;
|
||||
total_cost: string;
|
||||
cycle_type: MarketplaceOrderCycleTypeView;
|
||||
cycle_id: string | null;
|
||||
warranty_period_secs: number;
|
||||
warranty_until: string | null;
|
||||
status: MarketplaceOrderStatusView;
|
||||
last_status_reason: string | null;
|
||||
blocked_at: string | null;
|
||||
accepted_at: string | null;
|
||||
received_at: string | null;
|
||||
cancelled_at: string | null;
|
||||
type _RawOrder = _RawOrderPage['items'][number];
|
||||
|
||||
/**
|
||||
* Zeus маппит DateTime в `unknown`. Структуру/enum'ы оставляем из Zeus, но
|
||||
* скалярную дату создания переопределяем на строку для форматирования в UI.
|
||||
*/
|
||||
export type MarketplaceOrderView = Omit<_RawOrder, 'created_at'> & {
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
};
|
||||
|
||||
export interface MarketplaceOrderPage {
|
||||
/** Страница заказов: обёртка из Zeus, но items со строгой датой (см. MarketplaceOrderView). */
|
||||
export type MarketplaceOrderPage = Omit<_RawOrderPage, 'items'> & {
|
||||
items: MarketplaceOrderView[];
|
||||
totalCount: number;
|
||||
totalPages: number;
|
||||
currentPage: number;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Источник статусов/типов цикла — Zeus-enum'ы из @coopenomics/sdk. Берём
|
||||
* строковое значение поля Zeus-вывода (`${...}`), чтобы UI-карты статусов и
|
||||
* фильтры одинаково принимали и строковые литералы, и enum-значения из
|
||||
* самих заказов. Никаких параллельных строковых union'ов.
|
||||
*/
|
||||
export type MarketplaceOrderStatusView = `${MarketplaceOrderView['status']}`;
|
||||
|
||||
export type MarketplaceOrderCycleTypeView = `${MarketplaceOrderView['cycle_type']}`;
|
||||
|
||||
@@ -28,22 +28,26 @@ export async function fetchSupplierOrders(
|
||||
variables: ListSupplierOrdersVariables = {},
|
||||
): Promise<MarketplaceOrderPage> {
|
||||
const { page, limit, sortBy, sortOrder, statuses, orderer_account, offer_id } = variables;
|
||||
const result = await client.Query(Queries.Marketplace.ListSupplierOrders.query, {
|
||||
variables: {
|
||||
input: {
|
||||
orderer_account,
|
||||
offer_id,
|
||||
statuses,
|
||||
},
|
||||
options: {
|
||||
page: page ?? 1,
|
||||
limit: limit ?? 50,
|
||||
sortBy: sortBy ?? 'updated_at',
|
||||
sortOrder: sortOrder ?? 'DESC',
|
||||
const { [Queries.Marketplace.ListSupplierOrders.name]: result } = await client.Query(
|
||||
Queries.Marketplace.ListSupplierOrders.query,
|
||||
{
|
||||
variables: {
|
||||
input: {
|
||||
orderer_account,
|
||||
offer_id,
|
||||
statuses,
|
||||
},
|
||||
options: {
|
||||
page: page ?? 1,
|
||||
limit: limit ?? 50,
|
||||
sortBy: sortBy ?? 'updated_at',
|
||||
sortOrder: sortOrder ?? 'DESC',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
return result[Queries.Marketplace.ListSupplierOrders.name] as unknown as MarketplaceOrderPage;
|
||||
);
|
||||
// Zeus отдаёт DateTime как unknown; сужаем скалярную дату до строки во view-типе.
|
||||
return result as MarketplaceOrderPage;
|
||||
}
|
||||
|
||||
export async function acceptIndividualOrder(order_id: string): Promise<void> {
|
||||
|
||||
@@ -23,15 +23,18 @@ export async function fetchMyOffers(
|
||||
variables: ListMyOffersVariables = {},
|
||||
): Promise<MarketplaceOfferPage> {
|
||||
const { page, limit, sortBy, sortOrder } = variables;
|
||||
const result = await client.Query(Queries.Marketplace.ListMyOffers.query, {
|
||||
variables: {
|
||||
input: {
|
||||
page: page ?? 1,
|
||||
limit: limit ?? 50,
|
||||
sortBy: sortBy ?? 'updated_at',
|
||||
sortOrder: sortOrder ?? 'DESC',
|
||||
const { [Queries.Marketplace.ListMyOffers.name]: result } = await client.Query(
|
||||
Queries.Marketplace.ListMyOffers.query,
|
||||
{
|
||||
variables: {
|
||||
input: {
|
||||
page: page ?? 1,
|
||||
limit: limit ?? 50,
|
||||
sortBy: sortBy ?? 'updated_at',
|
||||
sortOrder: sortOrder ?? 'DESC',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
return result[Queries.Marketplace.ListMyOffers.name] as unknown as MarketplaceOfferPage;
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,55 +1,21 @@
|
||||
/**
|
||||
* Эпик 3 / Story 3.4: типы offerer-стола «Мои предложения».
|
||||
* Источник истины — backend MarketplaceOfferDTO + MarketplaceOfferStatuses.
|
||||
* Источник истины — Zeus-вывод операции marketplaceListMyOffers из @coopenomics/sdk.
|
||||
*/
|
||||
|
||||
export type MarketplaceOfferStatusView =
|
||||
| 'PENDING_MODERATION'
|
||||
| 'ACTIVE'
|
||||
| 'REJECTED'
|
||||
| 'WITHDRAWN';
|
||||
import { Queries } from '@coopenomics/sdk';
|
||||
|
||||
export type MarketplaceOfferCycleTypeView =
|
||||
| 'time_based'
|
||||
| 'volume_based'
|
||||
| 'open_subscription'
|
||||
| 'individual';
|
||||
export type MarketplaceOfferPage =
|
||||
Queries.Marketplace.ListMyOffers.IOutput['marketplaceListMyOffers'];
|
||||
|
||||
export interface MarketplaceOfferView {
|
||||
id: string;
|
||||
coopname: string;
|
||||
supplier_account: string;
|
||||
vitrine_id: string | null;
|
||||
product_name: string;
|
||||
description: string | null;
|
||||
category_id: string | null;
|
||||
price_per_unit: string;
|
||||
unit_of_measure: string;
|
||||
quantity_available: number;
|
||||
quantity_blocked: number;
|
||||
quantity_consumed: number;
|
||||
unlimited_flag: boolean;
|
||||
cycle_type: MarketplaceOfferCycleTypeView;
|
||||
cycle_days: number | null;
|
||||
target_volume: number | null;
|
||||
max_wait_days: number | null;
|
||||
min_threshold: number | null;
|
||||
warranty_days: number;
|
||||
barcode_strategy: string;
|
||||
pack_size: number | null;
|
||||
status: MarketplaceOfferStatusView;
|
||||
approved_by: string | null;
|
||||
approved_at: string | null;
|
||||
rejected_by: string | null;
|
||||
rejected_at: string | null;
|
||||
reject_reason: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
export type MarketplaceOfferView = MarketplaceOfferPage['items'][number];
|
||||
|
||||
export interface MarketplaceOfferPage {
|
||||
items: MarketplaceOfferView[];
|
||||
totalCount: number;
|
||||
totalPages: number;
|
||||
currentPage: number;
|
||||
}
|
||||
/**
|
||||
* Источник статусов/типов цикла — Zeus-enum'ы из @coopenomics/sdk. Берём
|
||||
* строковое значение поля Zeus-вывода (`${...}`), чтобы UI-карты статусов и
|
||||
* фильтры одинаково принимали и строковые литералы, и enum-значения из
|
||||
* самих предложений.
|
||||
*/
|
||||
export type MarketplaceOfferStatusView = `${MarketplaceOfferView['status']}`;
|
||||
|
||||
export type MarketplaceOfferCycleTypeView = `${MarketplaceOfferView['cycle_type']}`;
|
||||
|
||||
@@ -70,7 +70,7 @@ const cards = computed<Array<CatalogOffer & { domainStatus: MarketplaceOfferStat
|
||||
unitLabel: o.unit_of_measure,
|
||||
status: STATUS_TO_CARD[o.status],
|
||||
domainStatus: o.status,
|
||||
rejectReason: o.reject_reason,
|
||||
rejectReason: o.reject_reason ?? null,
|
||||
})),
|
||||
);
|
||||
|
||||
|
||||
@@ -1,29 +1,13 @@
|
||||
import { Queries } from '@coopenomics/sdk';
|
||||
import { client } from 'src/shared/api/client';
|
||||
|
||||
export interface MarketplaceOutgoingPaymentRequestView {
|
||||
id: string;
|
||||
coopname: string;
|
||||
apl_reception_id: string;
|
||||
payee_account: string;
|
||||
related_order_ids: string[];
|
||||
amount: string;
|
||||
symbol: string;
|
||||
purpose: string;
|
||||
status: string;
|
||||
confirmed_at: string | null;
|
||||
payment_reference: string | null;
|
||||
bank_statement_ref: string | null;
|
||||
blocked_reason: string | null;
|
||||
payout_tx_hash: string | null;
|
||||
core_payment_id: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
export type MarketplaceOutgoingPaymentRequestView =
|
||||
Queries.Marketplace.ListOutgoingPaymentsAsSupplier.IOutput['marketplaceListOutgoingPaymentsAsSupplier'][number];
|
||||
|
||||
export async function listMyPayments(): Promise<MarketplaceOutgoingPaymentRequestView[]> {
|
||||
const result = await client.Query(Queries.Marketplace.ListOutgoingPaymentsAsSupplier.query, {});
|
||||
return result[
|
||||
Queries.Marketplace.ListOutgoingPaymentsAsSupplier.name
|
||||
] as unknown as MarketplaceOutgoingPaymentRequestView[];
|
||||
const { [Queries.Marketplace.ListOutgoingPaymentsAsSupplier.name]: result } = await client.Query(
|
||||
Queries.Marketplace.ListOutgoingPaymentsAsSupplier.query,
|
||||
{},
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,52 +1,58 @@
|
||||
import { Mutations, Queries, type Types } from '@coopenomics/sdk';
|
||||
import { client } from 'src/shared/api/client';
|
||||
|
||||
export interface MarketplaceAplReceptionView {
|
||||
type _RawAplReception =
|
||||
Queries.Marketplace.ListAplReceptionsAsSupplier.IOutput['marketplaceListAplReceptionsAsSupplier'][number];
|
||||
|
||||
/**
|
||||
* Zeus маппит GraphQL-скаляры ID/DateTime в `unknown`. Структуру и enum'ы
|
||||
* (status/variant) оставляем из Zeus-вывода, но скалярные поля-идентификаторы
|
||||
* и даты переопределяем на строгие строковые типы, чтобы потребители в UI
|
||||
* (slice по id, форматирование дат) типизировались без unknown.
|
||||
*/
|
||||
export type MarketplaceAplReceptionView = Omit<
|
||||
_RawAplReception,
|
||||
'id' | 'shipment_id' | 'cycle_id' | 'created_at' | 'updated_at' | 'supplier_signed_at' | 'chairman_signed_at'
|
||||
> & {
|
||||
id: string;
|
||||
coopname: string;
|
||||
shipment_id: string;
|
||||
cycle_id: string;
|
||||
braname: string;
|
||||
offerer_account: string;
|
||||
variant: 'A' | 'B';
|
||||
status: string;
|
||||
fact_quantity_per_order: Array<{ order_id: string; fact_quantity: number }>;
|
||||
ttn_number: string | null;
|
||||
total_amount: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
supplier_signed_at: string | null;
|
||||
chairman_signed_at: string | null;
|
||||
}
|
||||
};
|
||||
|
||||
export type SignedDocumentInput = Types.Document.ISignedDocumentInput;
|
||||
export type MarketplaceAplReceptionDocumentView = Types.Document.IGeneratedDocument;
|
||||
|
||||
export async function listAplReceptionsAsSupplier(): Promise<MarketplaceAplReceptionView[]> {
|
||||
const result = await client.Query(Queries.Marketplace.ListAplReceptionsAsSupplier.query, {});
|
||||
return result[
|
||||
Queries.Marketplace.ListAplReceptionsAsSupplier.name
|
||||
] as unknown as MarketplaceAplReceptionView[];
|
||||
const { [Queries.Marketplace.ListAplReceptionsAsSupplier.name]: result } = await client.Query(
|
||||
Queries.Marketplace.ListAplReceptionsAsSupplier.query,
|
||||
{},
|
||||
);
|
||||
// Zeus отдаёт ID/DateTime как unknown; сужаем скаляры до строк во view-типе.
|
||||
return result as MarketplaceAplReceptionView[];
|
||||
}
|
||||
|
||||
export async function fetchSupplierSignablePayloads(
|
||||
apl_reception_id: string,
|
||||
): Promise<MarketplaceAplReceptionDocumentView[]> {
|
||||
const result = await client.Query(
|
||||
Queries.Marketplace.AplReceptionSupplierSignablePayloads.query,
|
||||
{ variables: { data: { apl_reception_id } } },
|
||||
);
|
||||
return result[
|
||||
Queries.Marketplace.AplReceptionSupplierSignablePayloads.name
|
||||
] as unknown as MarketplaceAplReceptionDocumentView[];
|
||||
const { [Queries.Marketplace.AplReceptionSupplierSignablePayloads.name]: result } =
|
||||
await client.Query(Queries.Marketplace.AplReceptionSupplierSignablePayloads.query, {
|
||||
variables: { data: { apl_reception_id } },
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function signAsSupplier(
|
||||
apl_reception_id: string,
|
||||
signed_documents: SignedDocumentInput[],
|
||||
): Promise<{ apl_reception: MarketplaceAplReceptionView }> {
|
||||
const result = await client.Mutation(Mutations.Marketplace.SignAplReceptionAsSupplier.mutation, {
|
||||
variables: { data: { apl_reception_id, signed_documents } },
|
||||
});
|
||||
return result[Mutations.Marketplace.SignAplReceptionAsSupplier.name] as unknown as {
|
||||
apl_reception: MarketplaceAplReceptionView;
|
||||
};
|
||||
const { [Mutations.Marketplace.SignAplReceptionAsSupplier.name]: result } =
|
||||
await client.Mutation(Mutations.Marketplace.SignAplReceptionAsSupplier.mutation, {
|
||||
variables: { data: { apl_reception_id, signed_documents } },
|
||||
});
|
||||
// Zeus отдаёт ID/DateTime как unknown; сужаем скаляры до строк во view-типе.
|
||||
return result as { apl_reception: MarketplaceAplReceptionView };
|
||||
}
|
||||
|
||||
@@ -1,54 +1,27 @@
|
||||
import { Mutations, Queries } from '@coopenomics/sdk';
|
||||
import { client } from 'src/shared/api/client';
|
||||
|
||||
export interface MarketplaceShipmentTTNDataView {
|
||||
expeditor_full_name: string;
|
||||
expeditor_id_doc: string;
|
||||
expeditor_phone: string;
|
||||
vehicle_number: string;
|
||||
loading_address: string;
|
||||
loading_datetime: string;
|
||||
delivery_datetime_estimate: string;
|
||||
}
|
||||
export type MarketplaceShipmentView =
|
||||
Queries.Marketplace.ListShipments.IOutput['marketplaceListShipments'][number];
|
||||
|
||||
export interface MarketplaceShipmentView {
|
||||
id: string;
|
||||
coopname: string;
|
||||
cycle_id: string;
|
||||
braname: string;
|
||||
offerer_account: string;
|
||||
delivery_variant: 'A' | 'B';
|
||||
status: string;
|
||||
total_amount: string;
|
||||
ttn_number: string | null;
|
||||
ttn_data: MarketplaceShipmentTTNDataView | null;
|
||||
ttn_document_id: string | null;
|
||||
}
|
||||
export type MarketplaceShipmentTTNDataView = NonNullable<MarketplaceShipmentView['ttn_data']>;
|
||||
|
||||
export async function listShipments(cycle_id?: string): Promise<MarketplaceShipmentView[]> {
|
||||
const result = await client.Query(Queries.Marketplace.ListShipments.query, {
|
||||
variables: { data: { cycle_id } },
|
||||
});
|
||||
return result[Queries.Marketplace.ListShipments.name] as unknown as MarketplaceShipmentView[];
|
||||
const { [Queries.Marketplace.ListShipments.name]: result } = await client.Query(
|
||||
Queries.Marketplace.ListShipments.query,
|
||||
{ variables: { data: { cycle_id } } },
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
export interface CreateShipmentVariables {
|
||||
cycle_id: string;
|
||||
groups: Array<{
|
||||
braname: string;
|
||||
delivery_variant: 'A' | 'B';
|
||||
order_ids: string[];
|
||||
ttn_data?: MarketplaceShipmentTTNDataView;
|
||||
}>;
|
||||
}
|
||||
export type CreateShipmentVariables = Mutations.Marketplace.CreateShipment.IInput['data'];
|
||||
|
||||
export async function createShipment(
|
||||
data: CreateShipmentVariables,
|
||||
): Promise<{ shipments: MarketplaceShipmentView[] }> {
|
||||
const result = await client.Mutation(Mutations.Marketplace.CreateShipment.mutation, {
|
||||
variables: { data },
|
||||
});
|
||||
return result[Mutations.Marketplace.CreateShipment.name] as unknown as {
|
||||
shipments: MarketplaceShipmentView[];
|
||||
};
|
||||
): Promise<Mutations.Marketplace.CreateShipment.IOutput['marketplaceCreateShipment']> {
|
||||
const { [Mutations.Marketplace.CreateShipment.name]: result } = await client.Mutation(
|
||||
Mutations.Marketplace.CreateShipment.mutation,
|
||||
{ variables: { data } },
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -17,12 +17,13 @@ export async function listShipmentsByBraname(
|
||||
return result;
|
||||
}
|
||||
|
||||
export interface MarketplaceOperatorBranchesView {
|
||||
username: string;
|
||||
branches: string[];
|
||||
}
|
||||
export type MarketplaceOperatorBranchesView =
|
||||
Queries.Marketplace.WhoAmI.IOutput['marketplaceWhoAmI'];
|
||||
|
||||
export async function fetchOperatorBranches(): Promise<MarketplaceOperatorBranchesView> {
|
||||
const result = await client.Query(Queries.Marketplace.WhoAmI.query, { variables: {} });
|
||||
return result[Queries.Marketplace.WhoAmI.name] as unknown as MarketplaceOperatorBranchesView;
|
||||
const { [Queries.Marketplace.WhoAmI.name]: result } = await client.Query(
|
||||
Queries.Marketplace.WhoAmI.query,
|
||||
{ variables: {} },
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -10,44 +10,26 @@ export interface MarketplaceOrderForLabeling {
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface MarketplaceInventoryItemView {
|
||||
id: string;
|
||||
barcode_value: string;
|
||||
barcode_format: 'CODE128' | 'EAN13';
|
||||
order_id: string;
|
||||
shipment_id: string;
|
||||
braname: string;
|
||||
status: 'LABELED' | 'ISSUED' | 'RETURNED' | 'WRITTEN_OFF';
|
||||
product_name_snapshot: string;
|
||||
quantity_per_label: number;
|
||||
orderer_account_snapshot: string;
|
||||
labeled_at: string;
|
||||
}
|
||||
// Zeus маппит скаляр ID в `unknown`; идентификатор переопределяем на строку
|
||||
// (используется как :key и для slice в UI).
|
||||
type _RawInventoryItem =
|
||||
Queries.Marketplace.ListInventory.IOutput['marketplaceListInventory'][number];
|
||||
export type MarketplaceInventoryItemView = Omit<_RawInventoryItem, 'id'> & { id: string };
|
||||
|
||||
export interface MarketplaceShipmentView {
|
||||
id: string;
|
||||
coopname: string;
|
||||
cycle_id: string;
|
||||
braname: string;
|
||||
offerer_account: string;
|
||||
delivery_variant: 'SELF_PICKUP' | 'EXPEDITOR' | string;
|
||||
status: string;
|
||||
total_amount: string;
|
||||
ttn_number: string | null;
|
||||
created_at: string;
|
||||
}
|
||||
type _RawShipment =
|
||||
Queries.Marketplace.ListShipments.IOutput['marketplaceListShipments'][number];
|
||||
export type MarketplaceShipmentView = Omit<_RawShipment, 'id'> & { id: string };
|
||||
|
||||
export interface MarketplaceLabelShipmentInventoryResultView {
|
||||
inventory: MarketplaceInventoryItemView[];
|
||||
labeled_order_ids: string[];
|
||||
skipped_order_ids: string[];
|
||||
}
|
||||
export type MarketplaceLabelShipmentInventoryResultView =
|
||||
Mutations.Marketplace.LabelShipmentInventory.IOutput['marketplaceLabelShipmentInventory'];
|
||||
|
||||
export async function fetchInventoryByBraname(braname: string): Promise<MarketplaceInventoryItemView[]> {
|
||||
const result = await client.Query(Queries.Marketplace.ListInventory.query, {
|
||||
variables: { data: { braname } },
|
||||
})
|
||||
return result[Queries.Marketplace.ListInventory.name] as unknown as MarketplaceInventoryItemView[]
|
||||
const { [Queries.Marketplace.ListInventory.name]: result } = await client.Query(
|
||||
Queries.Marketplace.ListInventory.query,
|
||||
{ variables: { data: { braname } } },
|
||||
)
|
||||
// Zeus отдаёт ID как unknown; сужаем идентификатор до строки во view-типе.
|
||||
return result as MarketplaceInventoryItemView[]
|
||||
}
|
||||
|
||||
const SHIPMENT_STATUSES_FOR_LABELING: Zeus.MarketplaceShipmentStatus[] = [
|
||||
@@ -60,26 +42,30 @@ export async function fetchShipmentsForLabeling(braname?: string): Promise<Marke
|
||||
statuses: SHIPMENT_STATUSES_FOR_LABELING,
|
||||
}
|
||||
if (braname) data.braname = braname
|
||||
const result = await client.Query(Queries.Marketplace.ListShipments.query, {
|
||||
variables: { data },
|
||||
})
|
||||
return result[Queries.Marketplace.ListShipments.name] as unknown as MarketplaceShipmentView[]
|
||||
const { [Queries.Marketplace.ListShipments.name]: result } = await client.Query(
|
||||
Queries.Marketplace.ListShipments.query,
|
||||
{ variables: { data } },
|
||||
)
|
||||
// Zeus отдаёт ID как unknown; сужаем идентификатор до строки во view-типе.
|
||||
return result as MarketplaceShipmentView[]
|
||||
}
|
||||
|
||||
export async function labelInventory(data: Mutations.Marketplace.LabelInventory.IInput['data']): Promise<{ inventory: MarketplaceInventoryItemView[] }> {
|
||||
const result = await client.Mutation(Mutations.Marketplace.LabelInventory.mutation, {
|
||||
variables: { data },
|
||||
})
|
||||
return result[Mutations.Marketplace.LabelInventory.name] as unknown as {
|
||||
inventory: MarketplaceInventoryItemView[];
|
||||
}
|
||||
export async function labelInventory(
|
||||
data: Mutations.Marketplace.LabelInventory.IInput['data'],
|
||||
): Promise<Mutations.Marketplace.LabelInventory.IOutput['marketplaceLabelInventory']> {
|
||||
const { [Mutations.Marketplace.LabelInventory.name]: result } = await client.Mutation(
|
||||
Mutations.Marketplace.LabelInventory.mutation,
|
||||
{ variables: { data } },
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
export async function labelShipmentInventory(
|
||||
data: Mutations.Marketplace.LabelShipmentInventory.IInput['data'],
|
||||
): Promise<MarketplaceLabelShipmentInventoryResultView> {
|
||||
const result = await client.Mutation(Mutations.Marketplace.LabelShipmentInventory.mutation, {
|
||||
variables: { data },
|
||||
})
|
||||
return result[Mutations.Marketplace.LabelShipmentInventory.name] as unknown as MarketplaceLabelShipmentInventoryResultView
|
||||
const { [Mutations.Marketplace.LabelShipmentInventory.name]: result } = await client.Mutation(
|
||||
Mutations.Marketplace.LabelShipmentInventory.mutation,
|
||||
{ variables: { data } },
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -13,9 +13,13 @@ export type MarketplaceOrderIssuanceFactView =
|
||||
* SDK через select из orderSelector (полный набор колонок Order вместе
|
||||
* с полями выдачи Эпика 6).
|
||||
*/
|
||||
export type MarketplaceOrderIssuanceView =
|
||||
type _RawOrderIssuance =
|
||||
Queries.Marketplace.ListMyReadyToReceive.IOutput['marketplaceListMyReadyToReceive'][number];
|
||||
|
||||
export type MarketplaceOrderIssuanceView = Omit<_RawOrderIssuance, 'created_at'> & {
|
||||
created_at: string;
|
||||
};
|
||||
|
||||
export type MarketplaceIssuanceResultView =
|
||||
Mutations.Marketplace.OpenIssuance.IOutput['marketplaceOpenIssuance'];
|
||||
|
||||
@@ -27,11 +31,18 @@ export type MarketplaceGeneratedDocumentView = Types.Document.IGeneratedDocument
|
||||
* уже наложенной подписью председателя (document). Заказчик накладывает
|
||||
* финальную подпись поверх, не перегенерируя документ.
|
||||
*/
|
||||
export interface MarketplaceIssuanceAggregateView {
|
||||
hash: string;
|
||||
rawDocument: Types.Document.IGeneratedDocument;
|
||||
document: Types.Document.ISignedDocument;
|
||||
}
|
||||
type _RawIssuanceAggregate =
|
||||
Queries.Marketplace.IssueActOrdererSignablePayload.IOutput['marketplaceIssueActOrdererSignablePayload'];
|
||||
|
||||
/**
|
||||
* Backend всегда возвращает исходный документ (`rawDocument`) в агрегате
|
||||
* подписываемой выдачи — заказчик накладывает финальную подпись поверх него.
|
||||
* В Zeus поле помечено опциональным; фиксируем как обязательное и
|
||||
* ненулевое для строгой типизации подписи.
|
||||
*/
|
||||
export type MarketplaceIssuanceAggregateView = Omit<_RawIssuanceAggregate, 'rawDocument'> & {
|
||||
rawDocument: NonNullable<_RawIssuanceAggregate['rawDocument']>;
|
||||
};
|
||||
|
||||
export async function listIssuancesByBraname(
|
||||
delivery_braname: string,
|
||||
@@ -40,7 +51,8 @@ export async function listIssuancesByBraname(
|
||||
Queries.Marketplace.ListIssuancesByBraname.query,
|
||||
{ variables: { data: { delivery_braname } } },
|
||||
);
|
||||
return result;
|
||||
// Zeus отдаёт DateTime как unknown; сужаем скалярную дату до строки во view-типе.
|
||||
return result as MarketplaceOrderIssuanceView[];
|
||||
}
|
||||
|
||||
export async function listMyReadyToReceive(): Promise<MarketplaceOrderIssuanceView[]> {
|
||||
@@ -48,7 +60,7 @@ export async function listMyReadyToReceive(): Promise<MarketplaceOrderIssuanceVi
|
||||
Queries.Marketplace.ListMyReadyToReceive.query,
|
||||
{},
|
||||
);
|
||||
return result;
|
||||
return result as MarketplaceOrderIssuanceView[];
|
||||
}
|
||||
|
||||
export async function getChairmanSignablePayload(
|
||||
@@ -68,7 +80,8 @@ export async function getOrdererSignablePayload(
|
||||
await client.Query(Queries.Marketplace.IssueActOrdererSignablePayload.query, {
|
||||
variables: { data: { order_id } },
|
||||
});
|
||||
return result as unknown as MarketplaceIssuanceAggregateView;
|
||||
// Backend всегда возвращает rawDocument; в Zeus оно опционально — фиксируем как обязательное.
|
||||
return result as MarketplaceIssuanceAggregateView;
|
||||
}
|
||||
|
||||
export async function openIssuance(
|
||||
|
||||
@@ -1,65 +1,61 @@
|
||||
import { Mutations, Queries, type Types } from '@coopenomics/sdk';
|
||||
import { Mutations, Queries } from '@coopenomics/sdk';
|
||||
import { client } from 'src/shared/api/client';
|
||||
import type { MarketplaceAplReceptionView, SignedDocumentInput } from '../../OffererPendingAplReceptions/api';
|
||||
|
||||
export type { MarketplaceAplReceptionView } from '../../OffererPendingAplReceptions/api';
|
||||
export type { MarketplaceAplReceptionView, SignedDocumentInput } from '../../OffererPendingAplReceptions/api';
|
||||
|
||||
/**
|
||||
* Агрегат документа: исходный документ (rawDocument) + документ с уже
|
||||
* наложенной подписью поставщика (document). Председатель накладывает
|
||||
* закрывающую подпись поверх, не перегенерируя документ.
|
||||
*/
|
||||
export interface MarketplaceDocumentAggregateView {
|
||||
hash: string;
|
||||
rawDocument: Types.Document.IGeneratedDocument;
|
||||
document: Types.Document.ISignedDocument;
|
||||
}
|
||||
type _RawDocumentAggregate =
|
||||
Queries.Marketplace.AplReceptionChairmanSignablePayloads.IOutput['marketplaceAplReceptionChairmanSignablePayloads'][number];
|
||||
|
||||
export type MarketplaceDocumentAggregateView = Omit<_RawDocumentAggregate, 'rawDocument'> & {
|
||||
rawDocument: NonNullable<_RawDocumentAggregate['rawDocument']>;
|
||||
};
|
||||
|
||||
export async function fetchChairmanSignablePayloads(
|
||||
apl_reception_id: string,
|
||||
): Promise<MarketplaceDocumentAggregateView[]> {
|
||||
const result = await client.Query(
|
||||
Queries.Marketplace.AplReceptionChairmanSignablePayloads.query,
|
||||
{ variables: { data: { apl_reception_id } } },
|
||||
);
|
||||
return result[
|
||||
Queries.Marketplace.AplReceptionChairmanSignablePayloads.name
|
||||
] as unknown as MarketplaceDocumentAggregateView[];
|
||||
const { [Queries.Marketplace.AplReceptionChairmanSignablePayloads.name]: result } =
|
||||
await client.Query(Queries.Marketplace.AplReceptionChairmanSignablePayloads.query, {
|
||||
variables: { data: { apl_reception_id } },
|
||||
});
|
||||
// Backend всегда возвращает rawDocument; в Zeus оно опционально — фиксируем как обязательное.
|
||||
return result as MarketplaceDocumentAggregateView[];
|
||||
}
|
||||
|
||||
export async function listAplReceptionsByBraname(braname: string): Promise<MarketplaceAplReceptionView[]> {
|
||||
const result = await client.Query(Queries.Marketplace.ListAplReceptionsByBraname.query, {
|
||||
variables: { data: { braname } },
|
||||
});
|
||||
return result[
|
||||
Queries.Marketplace.ListAplReceptionsByBraname.name
|
||||
] as unknown as MarketplaceAplReceptionView[];
|
||||
const { [Queries.Marketplace.ListAplReceptionsByBraname.name]: result } = await client.Query(
|
||||
Queries.Marketplace.ListAplReceptionsByBraname.query,
|
||||
{ variables: { data: { braname } } },
|
||||
);
|
||||
// Zeus отдаёт ID/DateTime как unknown; сужаем скаляры до строк во view-типе.
|
||||
return result as MarketplaceAplReceptionView[];
|
||||
}
|
||||
|
||||
export interface CreateAplReceptionVariables {
|
||||
shipment_id: string;
|
||||
fact_quantity_per_order?: Array<{ order_id: string; fact_quantity: number }>;
|
||||
}
|
||||
export type CreateAplReceptionVariables =
|
||||
Mutations.Marketplace.CreateAplReception.IInput['data'];
|
||||
|
||||
export async function createAplReception(
|
||||
data: CreateAplReceptionVariables,
|
||||
): Promise<{ apl_reception: MarketplaceAplReceptionView }> {
|
||||
const result = await client.Mutation(Mutations.Marketplace.CreateAplReception.mutation, {
|
||||
variables: { data },
|
||||
});
|
||||
return result[Mutations.Marketplace.CreateAplReception.name] as unknown as {
|
||||
apl_reception: MarketplaceAplReceptionView;
|
||||
};
|
||||
): Promise<Mutations.Marketplace.CreateAplReception.IOutput['marketplaceCreateAplReception']> {
|
||||
const { [Mutations.Marketplace.CreateAplReception.name]: result } = await client.Mutation(
|
||||
Mutations.Marketplace.CreateAplReception.mutation,
|
||||
{ variables: { data } },
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function signAsChairman(
|
||||
apl_reception_id: string,
|
||||
signed_documents: SignedDocumentInput[],
|
||||
): Promise<{ apl_reception: MarketplaceAplReceptionView }> {
|
||||
const result = await client.Mutation(Mutations.Marketplace.SignAplReceptionAsChairman.mutation, {
|
||||
variables: { data: { apl_reception_id, signed_documents } },
|
||||
});
|
||||
return result[Mutations.Marketplace.SignAplReceptionAsChairman.name] as unknown as {
|
||||
apl_reception: MarketplaceAplReceptionView;
|
||||
};
|
||||
): Promise<Mutations.Marketplace.SignAplReceptionAsChairman.IOutput['marketplaceSignAplReceptionAsChairman']> {
|
||||
const { [Mutations.Marketplace.SignAplReceptionAsChairman.name]: result } = await client.Mutation(
|
||||
Mutations.Marketplace.SignAplReceptionAsChairman.mutation,
|
||||
{ variables: { data: { apl_reception_id, signed_documents } } },
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -16,9 +16,14 @@ export function defectCategoryLabel(category?: string | null): string {
|
||||
return DEFECT_CATEGORY_LABELS[category] ?? category;
|
||||
}
|
||||
|
||||
export type MarketplaceReturnClaimView =
|
||||
type _RawReturnClaim =
|
||||
Queries.Marketplace.ListReturnClaimsByBraname.IOutput['marketplaceListReturnClaimsByBraname'][number];
|
||||
|
||||
/** DateTime из Zeus приходит как `unknown`; дату создания переопределяем на строку для UI. */
|
||||
export type MarketplaceReturnClaimView = Omit<_RawReturnClaim, 'created_at'> & {
|
||||
created_at: string;
|
||||
};
|
||||
|
||||
export type MarketplaceReturnClaimResultView =
|
||||
Mutations.Marketplace.ApproveReturnVisit.IOutput['marketplaceApproveReturnVisit'];
|
||||
|
||||
@@ -44,7 +49,8 @@ export async function listReturnClaimsByBraname(
|
||||
Queries.Marketplace.ListReturnClaimsByBraname.query,
|
||||
{ variables: { data } },
|
||||
);
|
||||
return result;
|
||||
// Zeus отдаёт DateTime как unknown; сужаем дату создания до строки во view-типе.
|
||||
return result as MarketplaceReturnClaimView[];
|
||||
}
|
||||
|
||||
export async function approveReturnVisit(
|
||||
|
||||
+11
-10
@@ -1,5 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { Zeus } from '@coopenomics/sdk';
|
||||
import { FailAlert } from 'src/shared/api';
|
||||
import {
|
||||
listReturnClaimsByBraname,
|
||||
@@ -29,17 +30,17 @@ const onSiteDialog = ref(false);
|
||||
const selectedClaim = ref<MarketplaceReturnClaimView | null>(null);
|
||||
|
||||
const pendingClaims = computed(() =>
|
||||
items.value.filter((c) => c.status === 'PENDING_CHAIRMAN_REVIEW'),
|
||||
items.value.filter((c) => c.status === Zeus.MarketplaceReturnClaimStatus.PENDING_CHAIRMAN_REVIEW),
|
||||
);
|
||||
const approvedClaims = computed(() =>
|
||||
items.value.filter((c) => c.status === 'APPROVED_FOR_VISIT'),
|
||||
items.value.filter((c) => c.status === Zeus.MarketplaceReturnClaimStatus.APPROVED_FOR_VISIT),
|
||||
);
|
||||
const archiveClaims = computed(() =>
|
||||
items.value.filter(
|
||||
(c) =>
|
||||
c.status === 'ACCEPTED_AT_VISIT' ||
|
||||
c.status === 'REJECTED_REMOTELY' ||
|
||||
c.status === 'REJECTED_AT_VISIT',
|
||||
c.status === Zeus.MarketplaceReturnClaimStatus.ACCEPTED_AT_VISIT ||
|
||||
c.status === Zeus.MarketplaceReturnClaimStatus.REJECTED_REMOTELY ||
|
||||
c.status === Zeus.MarketplaceReturnClaimStatus.REJECTED_AT_VISIT,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -84,15 +85,15 @@ function formatDateTime(value: unknown): string {
|
||||
|
||||
function humanStatus(status: MarketplaceReturnClaimView['status']): string {
|
||||
switch (status) {
|
||||
case 'PENDING_CHAIRMAN_REVIEW':
|
||||
case Zeus.MarketplaceReturnClaimStatus.PENDING_CHAIRMAN_REVIEW:
|
||||
return 'Ждёт удалённого рассмотрения';
|
||||
case 'APPROVED_FOR_VISIT':
|
||||
case Zeus.MarketplaceReturnClaimStatus.APPROVED_FOR_VISIT:
|
||||
return 'Очный визит одобрен';
|
||||
case 'ACCEPTED_AT_VISIT':
|
||||
case Zeus.MarketplaceReturnClaimStatus.ACCEPTED_AT_VISIT:
|
||||
return 'Возврат принят';
|
||||
case 'REJECTED_REMOTELY':
|
||||
case Zeus.MarketplaceReturnClaimStatus.REJECTED_REMOTELY:
|
||||
return 'Отказано удалённо';
|
||||
case 'REJECTED_AT_VISIT':
|
||||
case Zeus.MarketplaceReturnClaimStatus.REJECTED_AT_VISIT:
|
||||
return 'Отказано на месте';
|
||||
default:
|
||||
return status;
|
||||
|
||||
+9
-9
@@ -34,17 +34,17 @@ const loading = ref(false);
|
||||
let pollTimer: ReturnType<typeof setInterval> | null = null;
|
||||
|
||||
const CYCLE_TYPE_LABEL: Record<MarketplaceOrderCycleTypeView, string> = {
|
||||
time_based: 'По времени',
|
||||
volume_based: 'По объёму',
|
||||
open_subscription: 'Открытая подписка',
|
||||
individual: 'Индивидуальный',
|
||||
TIME_BASED: 'По времени',
|
||||
VOLUME_BASED: 'По объёму',
|
||||
OPEN_SUBSCRIPTION: 'Открытая подписка',
|
||||
INDIVIDUAL: 'Индивидуальный',
|
||||
};
|
||||
|
||||
const CYCLE_TYPE_HINT: Record<MarketplaceOrderCycleTypeView, string> = {
|
||||
time_based: 'Партия закрывается по таймеру; заказы внутри окна объединяются для одной поставки.',
|
||||
volume_based: 'Партия закрывается при достижении порога объёма заказов.',
|
||||
open_subscription: 'Открытый пул заказов; партии формируются по решению поставщика.',
|
||||
individual: 'Каждый заказ обслуживается поставщиком отдельно.',
|
||||
TIME_BASED: 'Партия закрывается по таймеру; заказы внутри окна объединяются для одной поставки.',
|
||||
VOLUME_BASED: 'Партия закрывается при достижении порога объёма заказов.',
|
||||
OPEN_SUBSCRIPTION: 'Открытый пул заказов; партии формируются по решению поставщика.',
|
||||
INDIVIDUAL: 'Каждый заказ обслуживается поставщиком отдельно.',
|
||||
};
|
||||
|
||||
const STATUS_LABEL: Record<MarketplaceOrderStatusView, string> = {
|
||||
@@ -121,7 +121,7 @@ const groups = computed<ConsolidatedGroup[]>(() => {
|
||||
if (!g) {
|
||||
g = {
|
||||
key,
|
||||
cycle_id: o.cycle_id,
|
||||
cycle_id: o.cycle_id ?? null,
|
||||
cycle_type: o.cycle_type,
|
||||
offer_id: o.offer_id,
|
||||
supplier_account: o.supplier_account,
|
||||
|
||||
@@ -12,5 +12,6 @@ export async function listMyReadyToReceive(): Promise<MarketplaceOrderIssuanceVi
|
||||
Queries.Marketplace.ListMyReadyToReceive.query,
|
||||
{},
|
||||
);
|
||||
return result;
|
||||
// Zeus отдаёт DateTime как unknown; сужаем скалярную дату до строки во view-типе.
|
||||
return result as MarketplaceOrderIssuanceView[];
|
||||
}
|
||||
|
||||
+22
-15
@@ -1,5 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { Zeus } from '@coopenomics/sdk';
|
||||
import { FailAlert } from 'src/shared/api';
|
||||
import { listMyReturnClaims, type MarketplaceReturnClaimView } from '../api';
|
||||
import { fetchMyOrders } from '../../MyOrders/api';
|
||||
@@ -35,7 +36,11 @@ const selectedClaim = ref<MarketplaceReturnClaimView | null>(null);
|
||||
const orderOptions = computed(() => {
|
||||
const openOrderIds = new Set(
|
||||
items.value
|
||||
.filter((c) => c.status === 'PENDING_CHAIRMAN_REVIEW' || c.status === 'APPROVED_FOR_VISIT')
|
||||
.filter(
|
||||
(c) =>
|
||||
c.status === Zeus.MarketplaceReturnClaimStatus.PENDING_CHAIRMAN_REVIEW ||
|
||||
c.status === Zeus.MarketplaceReturnClaimStatus.APPROVED_FOR_VISIT,
|
||||
)
|
||||
.map((c) => c.order_id),
|
||||
);
|
||||
return eligibleOrders.value
|
||||
@@ -48,15 +53,17 @@ const orderOptions = computed(() => {
|
||||
|
||||
const activeClaims = computed(() =>
|
||||
items.value.filter(
|
||||
(c) => c.status === 'PENDING_CHAIRMAN_REVIEW' || c.status === 'APPROVED_FOR_VISIT',
|
||||
(c) =>
|
||||
c.status === Zeus.MarketplaceReturnClaimStatus.PENDING_CHAIRMAN_REVIEW ||
|
||||
c.status === Zeus.MarketplaceReturnClaimStatus.APPROVED_FOR_VISIT,
|
||||
),
|
||||
);
|
||||
const archiveClaims = computed(() =>
|
||||
items.value.filter(
|
||||
(c) =>
|
||||
c.status === 'ACCEPTED_AT_VISIT' ||
|
||||
c.status === 'REJECTED_REMOTELY' ||
|
||||
c.status === 'REJECTED_AT_VISIT',
|
||||
c.status === Zeus.MarketplaceReturnClaimStatus.ACCEPTED_AT_VISIT ||
|
||||
c.status === Zeus.MarketplaceReturnClaimStatus.REJECTED_REMOTELY ||
|
||||
c.status === Zeus.MarketplaceReturnClaimStatus.REJECTED_AT_VISIT,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -104,15 +111,15 @@ function onSubmitted(): void {
|
||||
|
||||
function humanStatus(status: MarketplaceReturnClaimView['status']): string {
|
||||
switch (status) {
|
||||
case 'PENDING_CHAIRMAN_REVIEW':
|
||||
case Zeus.MarketplaceReturnClaimStatus.PENDING_CHAIRMAN_REVIEW:
|
||||
return 'На рассмотрении председателя';
|
||||
case 'APPROVED_FOR_VISIT':
|
||||
case Zeus.MarketplaceReturnClaimStatus.APPROVED_FOR_VISIT:
|
||||
return 'Очный визит одобрен';
|
||||
case 'ACCEPTED_AT_VISIT':
|
||||
case Zeus.MarketplaceReturnClaimStatus.ACCEPTED_AT_VISIT:
|
||||
return 'Возврат принят';
|
||||
case 'REJECTED_REMOTELY':
|
||||
case Zeus.MarketplaceReturnClaimStatus.REJECTED_REMOTELY:
|
||||
return 'Отказано удалённо';
|
||||
case 'REJECTED_AT_VISIT':
|
||||
case Zeus.MarketplaceReturnClaimStatus.REJECTED_AT_VISIT:
|
||||
return 'Отказано на месте';
|
||||
default:
|
||||
return status;
|
||||
@@ -128,14 +135,14 @@ function formatDate(value: unknown): string {
|
||||
|
||||
function statusColor(status: MarketplaceReturnClaimView['status']): string {
|
||||
switch (status) {
|
||||
case 'PENDING_CHAIRMAN_REVIEW':
|
||||
case Zeus.MarketplaceReturnClaimStatus.PENDING_CHAIRMAN_REVIEW:
|
||||
return 'primary';
|
||||
case 'APPROVED_FOR_VISIT':
|
||||
case Zeus.MarketplaceReturnClaimStatus.APPROVED_FOR_VISIT:
|
||||
return 'info';
|
||||
case 'ACCEPTED_AT_VISIT':
|
||||
case Zeus.MarketplaceReturnClaimStatus.ACCEPTED_AT_VISIT:
|
||||
return 'positive';
|
||||
case 'REJECTED_REMOTELY':
|
||||
case 'REJECTED_AT_VISIT':
|
||||
case Zeus.MarketplaceReturnClaimStatus.REJECTED_REMOTELY:
|
||||
case Zeus.MarketplaceReturnClaimStatus.REJECTED_AT_VISIT:
|
||||
return 'negative';
|
||||
default:
|
||||
return 'grey';
|
||||
|
||||
@@ -5,10 +5,7 @@ export const name = 'marketplaceListOutgoingPayments'
|
||||
|
||||
export const query = Selector('Query')({
|
||||
[name]: [
|
||||
{
|
||||
supplier_account: $('supplier_account', 'String'),
|
||||
statuses: $('statuses', '[MarketplaceOutgoingPaymentRequestStatus!]'),
|
||||
},
|
||||
{ filter: $('filter', 'MarketplaceListOutgoingPaymentsFilterInput') },
|
||||
marketplaceOutgoingPaymentRequestSelector,
|
||||
],
|
||||
})
|
||||
@@ -19,8 +16,7 @@ export interface IInput {
|
||||
*/
|
||||
[key: string]: unknown
|
||||
|
||||
supplier_account?: string
|
||||
statuses?: ModelTypes['MarketplaceOutgoingPaymentRequestStatus'][]
|
||||
filter?: ModelTypes['MarketplaceListOutgoingPaymentsFilterInput']
|
||||
}
|
||||
|
||||
export type IOutput = InputType<GraphQLTypes['Query'], typeof query>
|
||||
|
||||
@@ -5,7 +5,7 @@ export const name = 'marketplaceListOutgoingPaymentsAsSupplier'
|
||||
|
||||
export const query = Selector('Query')({
|
||||
[name]: [
|
||||
{ statuses: $('statuses', '[MarketplaceOutgoingPaymentRequestStatus!]') },
|
||||
{ filter: $('filter', 'MarketplaceListOutgoingPaymentsAsSupplierFilterInput') },
|
||||
marketplaceOutgoingPaymentRequestSelector,
|
||||
],
|
||||
})
|
||||
@@ -16,7 +16,7 @@ export interface IInput {
|
||||
*/
|
||||
[key: string]: unknown
|
||||
|
||||
statuses?: ModelTypes['MarketplaceOutgoingPaymentRequestStatus'][]
|
||||
filter?: ModelTypes['MarketplaceListOutgoingPaymentsAsSupplierFilterInput']
|
||||
}
|
||||
|
||||
export type IOutput = InputType<GraphQLTypes['Query'], typeof query>
|
||||
|
||||
@@ -754,6 +754,12 @@ export const AllTypesProps: Record<string,any> = {
|
||||
MarketplaceListOrdersInput:{
|
||||
statuses:"MarketplaceOrderStatus"
|
||||
},
|
||||
MarketplaceListOutgoingPaymentsAsSupplierFilterInput:{
|
||||
statuses:"MarketplaceOutgoingPaymentRequestStatus"
|
||||
},
|
||||
MarketplaceListOutgoingPaymentsFilterInput:{
|
||||
statuses:"MarketplaceOutgoingPaymentRequestStatus"
|
||||
},
|
||||
MarketplaceListPendingOffersInput:{
|
||||
|
||||
},
|
||||
@@ -1980,10 +1986,10 @@ export const AllTypesProps: Record<string,any> = {
|
||||
options:"PaginationInput"
|
||||
},
|
||||
marketplaceListOutgoingPayments:{
|
||||
statuses:"MarketplaceOutgoingPaymentRequestStatus"
|
||||
filter:"MarketplaceListOutgoingPaymentsFilterInput"
|
||||
},
|
||||
marketplaceListOutgoingPaymentsAsSupplier:{
|
||||
statuses:"MarketplaceOutgoingPaymentRequestStatus"
|
||||
filter:"MarketplaceListOutgoingPaymentsAsSupplierFilterInput"
|
||||
},
|
||||
marketplaceListPendingOffers:{
|
||||
input:"MarketplaceListPendingOffersInput"
|
||||
|
||||
@@ -6866,6 +6866,16 @@ export type ValueTypes = {
|
||||
statuses?: Array<ValueTypes["MarketplaceOrderStatus"]> | undefined | null | Variable<any, string>,
|
||||
/** Фильтр по аккаунту поставщика. */
|
||||
supplier_account?: string | undefined | null | Variable<any, string>
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<ValueTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null | Variable<any, string>
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<ValueTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null | Variable<any, string>,
|
||||
/** Поставщик-получатель выплаты. Пусто — по всем поставщикам. */
|
||||
supplier_account?: string | undefined | null | Variable<any, string>
|
||||
};
|
||||
["MarketplaceListPendingOffersInput"]: {
|
||||
/** Количество элементов на странице */
|
||||
@@ -9594,8 +9604,8 @@ marketplaceListMyOrders?: [{ input?: ValueTypes["MarketplaceListOrdersInput"] |
|
||||
marketplaceListMyReadyToReceive?:ValueTypes["MarketplaceOrder"],
|
||||
/** Все заявления текущего пайщика на гарантийный возврат — активные и архивные. */
|
||||
marketplaceListMyReturnClaims?:ValueTypes["MarketplaceReturnClaim"],
|
||||
marketplaceListOutgoingPayments?: [{ statuses?: Array<ValueTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null | Variable<any, string>, supplier_account?: string | undefined | null | Variable<any, string>},ValueTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListOutgoingPaymentsAsSupplier?: [{ statuses?: Array<ValueTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null | Variable<any, string>},ValueTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListOutgoingPayments?: [{ filter?: ValueTypes["MarketplaceListOutgoingPaymentsFilterInput"] | undefined | null | Variable<any, string>},ValueTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListOutgoingPaymentsAsSupplier?: [{ filter?: ValueTypes["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"] | undefined | null | Variable<any, string>},ValueTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListPendingOffers?: [{ input?: ValueTypes["MarketplaceListPendingOffersInput"] | undefined | null | Variable<any, string>},ValueTypes["MarketplaceOfferPaginationResult"]],
|
||||
marketplaceListReturnClaimsByBraname?: [{ data: ValueTypes["MarketplaceListReturnClaimsByBranameInput"] | Variable<any, string>},ValueTypes["MarketplaceReturnClaim"]],
|
||||
marketplaceListShipments?: [{ data?: ValueTypes["MarketplaceListShipmentsInput"] | undefined | null | Variable<any, string>},ValueTypes["MarketplaceShipment"]],
|
||||
@@ -16818,6 +16828,16 @@ export type ResolverInputTypes = {
|
||||
statuses?: Array<ResolverInputTypes["MarketplaceOrderStatus"]> | undefined | null,
|
||||
/** Фильтр по аккаунту поставщика. */
|
||||
supplier_account?: string | undefined | null
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<ResolverInputTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<ResolverInputTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null,
|
||||
/** Поставщик-получатель выплаты. Пусто — по всем поставщикам. */
|
||||
supplier_account?: string | undefined | null
|
||||
};
|
||||
["MarketplaceListPendingOffersInput"]: {
|
||||
/** Количество элементов на странице */
|
||||
@@ -19449,8 +19469,8 @@ marketplaceListMyOrders?: [{ input?: ResolverInputTypes["MarketplaceListOrdersIn
|
||||
marketplaceListMyReadyToReceive?:ResolverInputTypes["MarketplaceOrder"],
|
||||
/** Все заявления текущего пайщика на гарантийный возврат — активные и архивные. */
|
||||
marketplaceListMyReturnClaims?:ResolverInputTypes["MarketplaceReturnClaim"],
|
||||
marketplaceListOutgoingPayments?: [{ statuses?: Array<ResolverInputTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null, supplier_account?: string | undefined | null},ResolverInputTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListOutgoingPaymentsAsSupplier?: [{ statuses?: Array<ResolverInputTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null},ResolverInputTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListOutgoingPayments?: [{ filter?: ResolverInputTypes["MarketplaceListOutgoingPaymentsFilterInput"] | undefined | null},ResolverInputTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListOutgoingPaymentsAsSupplier?: [{ filter?: ResolverInputTypes["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"] | undefined | null},ResolverInputTypes["MarketplaceOutgoingPaymentRequest"]],
|
||||
marketplaceListPendingOffers?: [{ input?: ResolverInputTypes["MarketplaceListPendingOffersInput"] | undefined | null},ResolverInputTypes["MarketplaceOfferPaginationResult"]],
|
||||
marketplaceListReturnClaimsByBraname?: [{ data: ResolverInputTypes["MarketplaceListReturnClaimsByBranameInput"]},ResolverInputTypes["MarketplaceReturnClaim"]],
|
||||
marketplaceListShipments?: [{ data?: ResolverInputTypes["MarketplaceListShipmentsInput"] | undefined | null},ResolverInputTypes["MarketplaceShipment"]],
|
||||
@@ -26449,6 +26469,16 @@ export type ModelTypes = {
|
||||
statuses?: Array<ModelTypes["MarketplaceOrderStatus"]> | undefined | null,
|
||||
/** Фильтр по аккаунту поставщика. */
|
||||
supplier_account?: string | undefined | null
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<ModelTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<ModelTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null,
|
||||
/** Поставщик-получатель выплаты. Пусто — по всем поставщикам. */
|
||||
supplier_account?: string | undefined | null
|
||||
};
|
||||
["MarketplaceListPendingOffersInput"]: {
|
||||
/** Количество элементов на странице */
|
||||
@@ -36996,6 +37026,16 @@ export type GraphQLTypes = {
|
||||
statuses?: Array<GraphQLTypes["MarketplaceOrderStatus"]> | undefined | null,
|
||||
/** Фильтр по аккаунту поставщика. */
|
||||
supplier_account?: string | undefined | null
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<GraphQLTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null
|
||||
};
|
||||
["MarketplaceListOutgoingPaymentsFilterInput"]: {
|
||||
/** Фильтр по статусам выплат. Пусто — показывать все статусы. */
|
||||
statuses?: Array<GraphQLTypes["MarketplaceOutgoingPaymentRequestStatus"]> | undefined | null,
|
||||
/** Поставщик-получатель выплаты. Пусто — по всем поставщикам. */
|
||||
supplier_account?: string | undefined | null
|
||||
};
|
||||
["MarketplaceListPendingOffersInput"]: {
|
||||
/** Количество элементов на странице */
|
||||
@@ -42933,6 +42973,8 @@ type ZEUS_VARIABLES = {
|
||||
["MarketplaceListIssuancesByBranameInput"]: ValueTypes["MarketplaceListIssuancesByBranameInput"];
|
||||
["MarketplaceListMyOffersInput"]: ValueTypes["MarketplaceListMyOffersInput"];
|
||||
["MarketplaceListOrdersInput"]: ValueTypes["MarketplaceListOrdersInput"];
|
||||
["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"]: ValueTypes["MarketplaceListOutgoingPaymentsAsSupplierFilterInput"];
|
||||
["MarketplaceListOutgoingPaymentsFilterInput"]: ValueTypes["MarketplaceListOutgoingPaymentsFilterInput"];
|
||||
["MarketplaceListPendingOffersInput"]: ValueTypes["MarketplaceListPendingOffersInput"];
|
||||
["MarketplaceListReturnClaimsByBranameInput"]: ValueTypes["MarketplaceListReturnClaimsByBranameInput"];
|
||||
["MarketplaceListShipmentsByBranameInput"]: ValueTypes["MarketplaceListShipmentsByBranameInput"];
|
||||
|
||||
Reference in New Issue
Block a user