[598-24][@ant] feat: read-only лента выплат поставщикам для совета (Payment:read:all) — закрыть placeholder-дыру на board/payouts-readonly реальным coop-wide обзором расчётов
- access-matrix: capability Payment:read:all для admin/board_readonly/board (член совета ведёт надзор за выплатами, подтверждает кассир)
- резолвер marketplaceListOutgoingPayments(supplier_account?, statuses?) под RequireMarketplaceAccess('Payment','read:all')
- repository.listAll(coopname, filter) + адаптер: coopname + опц. payee_account + In(statuses), created_at DESC
- SDK: Queries.Marketplace.ListOutgoingPayments + regen zeus (controller/zeus, sdk/src/zeus)
- desktop: BoardPayoutsReadonly с placeholder на реальную таблицу (фильтры поставщик/статус, сводка-счётчики, локализация статусов)
- harness-сценарий marketplace/board/payouts-readonly
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+5
@@ -81,6 +81,7 @@ export const marketplaceAccessMatrix: Record<MarketplaceRole, Record<string, str
|
||||
Vitrine: ['manage', 'read'],
|
||||
Warehouse: ['read:all'],
|
||||
Shipment: ['read:all'],
|
||||
Payment: ['read:all'],
|
||||
Extension: ['configure'],
|
||||
// Эпик 8: общий администратор формирует и редактирует DRAFT-проект
|
||||
// списания, подписывает Заявление 1106 и отправляет проект в совет.
|
||||
@@ -92,6 +93,9 @@ export const marketplaceAccessMatrix: Record<MarketplaceRole, Record<string, str
|
||||
Offer: ['read:all'],
|
||||
Agenda: ['read'],
|
||||
Writeoff: ['read:all'],
|
||||
// Совет ведёт read-only надзор за расчётами кооператива с поставщиками:
|
||||
// подтверждение/отказ выплат делает кассир, совету нужен только обзор.
|
||||
Payment: ['read:all'],
|
||||
},
|
||||
board: {
|
||||
Agenda: ['manage'],
|
||||
@@ -100,6 +104,7 @@ export const marketplaceAccessMatrix: Record<MarketplaceRole, Record<string, str
|
||||
// capability-маркер для UI «может ли роль видеть и принимать решение».
|
||||
Writeoff: ['decide', 'read:all'],
|
||||
Decision: ['create', 'sign'],
|
||||
Payment: ['read:all'],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
+24
@@ -3,7 +3,9 @@ import { Args, Query, Resolver } from '@nestjs/graphql';
|
||||
import config from '~/config/config';
|
||||
import { GqlJwtAuthGuard } from '~/application/auth/guards/graphql-jwt-auth.guard';
|
||||
import { CurrentMarketplaceMember } from '../decorators/current-marketplace-member.decorator';
|
||||
import { RequireMarketplaceAccess } from '../decorators/marketplace-access.decorator';
|
||||
import { MarketplaceMembershipGuard } from '../guards/marketplace-membership.guard';
|
||||
import { MarketplaceRoleGuard } from '../guards/marketplace-role.guard';
|
||||
import type { IMarketplaceCurrentMember } from '../dto/marketplace-current-member.dto';
|
||||
import {
|
||||
MarketplaceOutgoingPaymentRequestDTO,
|
||||
@@ -51,4 +53,26 @@ export class MarketplaceOutgoingPaymentResolver {
|
||||
);
|
||||
return list.map(toMarketplaceOutgoingPaymentRequestDTO);
|
||||
}
|
||||
|
||||
@Query(() => [MarketplaceOutgoingPaymentRequestDTO], {
|
||||
name: 'marketplaceListOutgoingPayments',
|
||||
description:
|
||||
'Лента выплат поставщикам по всему кооперативу — для совета. Опциональные фильтры: по поставщику-получателю и по статусам.',
|
||||
})
|
||||
@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[]
|
||||
): Promise<MarketplaceOutgoingPaymentRequestDTO[]> {
|
||||
const list = await this.paymentRepo.listAll(config.coopname, {
|
||||
payee_account: supplier_account ?? undefined,
|
||||
statuses: statuses as unknown as MarketplaceOutgoingPaymentRequestStatus[] | undefined,
|
||||
});
|
||||
return list.map(toMarketplaceOutgoingPaymentRequestDTO);
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -47,6 +47,19 @@ export interface MarketplaceOutgoingPaymentRequestDomainRepository {
|
||||
statuses?: MarketplaceOutgoingPaymentRequestStatus[]
|
||||
): Promise<MarketplaceOutgoingPaymentRequestDomainEntity[]>;
|
||||
|
||||
/**
|
||||
* Лента выплат по всему кооперативу для совета (read:all). Опциональные
|
||||
* фильтры по поставщику-получателю и статусам. В отличие от listByPayee
|
||||
* не привязана к текущему пайщику.
|
||||
*/
|
||||
listAll(
|
||||
coopname: string,
|
||||
filter?: {
|
||||
payee_account?: string;
|
||||
statuses?: MarketplaceOutgoingPaymentRequestStatus[];
|
||||
}
|
||||
): Promise<MarketplaceOutgoingPaymentRequestDomainEntity[]>;
|
||||
|
||||
/**
|
||||
* Переход PENDING → COMPLETED. Listener `action::marketplace::payconfirm`.
|
||||
* Идемпотентен — повторный вызов не меняет уже COMPLETED-запись.
|
||||
|
||||
+14
@@ -82,6 +82,20 @@ export class MarketplaceOutgoingPaymentRequestRepositoryAdapter
|
||||
return rows.map((r) => this.mapper.toDomain(r));
|
||||
}
|
||||
|
||||
async listAll(
|
||||
coopname: string,
|
||||
filter?: {
|
||||
payee_account?: string;
|
||||
statuses?: MarketplaceOutgoingPaymentRequestStatus[];
|
||||
}
|
||||
): Promise<MarketplaceOutgoingPaymentRequestDomainEntity[]> {
|
||||
const where: Record<string, unknown> = { coopname };
|
||||
if (filter?.payee_account) where.payee_account = filter.payee_account;
|
||||
if (filter?.statuses && filter.statuses.length > 0) where.status = In(filter.statuses);
|
||||
const rows = await this.repo.find({ where, order: { created_at: 'DESC' } });
|
||||
return rows.map((r) => this.mapper.toDomain(r));
|
||||
}
|
||||
|
||||
async applyCompletion(
|
||||
coopname: string,
|
||||
order_hash: string,
|
||||
|
||||
@@ -1979,6 +1979,9 @@ export const AllTypesProps: Record<string,any> = {
|
||||
input:"MarketplaceListOrdersInput",
|
||||
options:"PaginationInput"
|
||||
},
|
||||
marketplaceListOutgoingPayments:{
|
||||
statuses:"MarketplaceOutgoingPaymentRequestStatus"
|
||||
},
|
||||
marketplaceListOutgoingPaymentsAsSupplier:{
|
||||
statuses:"MarketplaceOutgoingPaymentRequestStatus"
|
||||
},
|
||||
@@ -5350,6 +5353,7 @@ export const ReturnTypes: Record<string,any> = {
|
||||
marketplaceListMyOrders:"MarketplaceOrderPaginationResult",
|
||||
marketplaceListMyReadyToReceive:"MarketplaceOrder",
|
||||
marketplaceListMyReturnClaims:"MarketplaceReturnClaim",
|
||||
marketplaceListOutgoingPayments:"MarketplaceOutgoingPaymentRequest",
|
||||
marketplaceListOutgoingPaymentsAsSupplier:"MarketplaceOutgoingPaymentRequest",
|
||||
marketplaceListPendingOffers:"MarketplaceOfferPaginationResult",
|
||||
marketplaceListReturnClaimsByBraname:"MarketplaceReturnClaim",
|
||||
|
||||
@@ -9594,6 +9594,7 @@ 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"]],
|
||||
marketplaceListPendingOffers?: [{ input?: ValueTypes["MarketplaceListPendingOffersInput"] | undefined | null | Variable<any, string>},ValueTypes["MarketplaceOfferPaginationResult"]],
|
||||
marketplaceListReturnClaimsByBraname?: [{ data: ValueTypes["MarketplaceListReturnClaimsByBranameInput"] | Variable<any, string>},ValueTypes["MarketplaceReturnClaim"]],
|
||||
@@ -19448,6 +19449,7 @@ 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"]],
|
||||
marketplaceListPendingOffers?: [{ input?: ResolverInputTypes["MarketplaceListPendingOffersInput"] | undefined | null},ResolverInputTypes["MarketplaceOfferPaginationResult"]],
|
||||
marketplaceListReturnClaimsByBraname?: [{ data: ResolverInputTypes["MarketplaceListReturnClaimsByBranameInput"]},ResolverInputTypes["MarketplaceReturnClaim"]],
|
||||
@@ -29691,6 +29693,8 @@ export type ModelTypes = {
|
||||
marketplaceListMyReadyToReceive: Array<ModelTypes["MarketplaceOrder"]>,
|
||||
/** Все заявления текущего пайщика на гарантийный возврат — активные и архивные. */
|
||||
marketplaceListMyReturnClaims: Array<ModelTypes["MarketplaceReturnClaim"]>,
|
||||
/** Лента выплат поставщикам по всему кооперативу — для совета. Опциональные фильтры: по поставщику-получателю и по статусам. */
|
||||
marketplaceListOutgoingPayments: Array<ModelTypes["MarketplaceOutgoingPaymentRequest"]>,
|
||||
/** История выплат поставщику в столе поставщика — статусы по каждому заказу. */
|
||||
marketplaceListOutgoingPaymentsAsSupplier: Array<ModelTypes["MarketplaceOutgoingPaymentRequest"]>,
|
||||
/** Список Offer'ов на модерации (admin) */
|
||||
@@ -40462,6 +40466,8 @@ export type GraphQLTypes = {
|
||||
marketplaceListMyReadyToReceive: Array<GraphQLTypes["MarketplaceOrder"]>,
|
||||
/** Все заявления текущего пайщика на гарантийный возврат — активные и архивные. */
|
||||
marketplaceListMyReturnClaims: Array<GraphQLTypes["MarketplaceReturnClaim"]>,
|
||||
/** Лента выплат поставщикам по всему кооперативу — для совета. Опциональные фильтры: по поставщику-получателю и по статусам. */
|
||||
marketplaceListOutgoingPayments: Array<GraphQLTypes["MarketplaceOutgoingPaymentRequest"]>,
|
||||
/** История выплат поставщику в столе поставщика — статусы по каждому заказу. */
|
||||
marketplaceListOutgoingPaymentsAsSupplier: Array<GraphQLTypes["MarketplaceOutgoingPaymentRequest"]>,
|
||||
/** Список Offer'ов на модерации (admin) */
|
||||
|
||||
@@ -279,10 +279,10 @@ export default async function (): Promise<IWorkspaceConfig[]> {
|
||||
},
|
||||
},
|
||||
{
|
||||
// Эпик 5 / Story 5.x: informational placeholder для совета —
|
||||
// лента выплат всех поставщиков. Текущий backend отдаёт только
|
||||
// выплаты текущего пайщика-supplier'а; для совета нужна доп.
|
||||
// query с read:all policy. Подключится в Phase 2.
|
||||
// Эпик 5 / Story 5.x: read-only лента выплат поставщикам по всему
|
||||
// кооперативу для совета. Backend marketplaceListOutgoingPayments
|
||||
// под capability Payment:read:all (board/board_readonly/admin),
|
||||
// опциональный фильтр по поставщику. Подтверждает выплаты кассир.
|
||||
path: 'payouts',
|
||||
name: 'marketplace-board-payouts',
|
||||
component: markRaw(BoardPayoutsReadonlyPage),
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Queries } from '@coopenomics/sdk';
|
||||
import { client } from 'src/shared/api/client';
|
||||
|
||||
export type MarketplaceOutgoingPaymentView =
|
||||
Queries.Marketplace.ListOutgoingPayments.IOutput['marketplaceListOutgoingPayments'][number];
|
||||
|
||||
export type IListOutgoingPaymentsInput = Queries.Marketplace.ListOutgoingPayments.IInput;
|
||||
|
||||
export async function listOutgoingPayments(
|
||||
input?: IListOutgoingPaymentsInput,
|
||||
): Promise<MarketplaceOutgoingPaymentView[]> {
|
||||
const { [Queries.Marketplace.ListOutgoingPayments.name]: result } = await client.Query(
|
||||
Queries.Marketplace.ListOutgoingPayments.query,
|
||||
{ variables: input ?? {} },
|
||||
);
|
||||
return result;
|
||||
}
|
||||
+126
-52
@@ -1,68 +1,142 @@
|
||||
<script lang="ts" setup>
|
||||
/**
|
||||
* Эпик 5 / Story 5.x: read-only лента выплат поставщикам для совета.
|
||||
*
|
||||
* Текущий backend (`marketplaceListOutgoingPaymentsAsSupplier`) фильтрует
|
||||
* по `member.username` — каждый поставщик видит только свои выплаты.
|
||||
* Для совета (видит выплаты всех поставщиков) нужно дополнить:
|
||||
* 1. Добавить `Payment` policy в marketplace-access-matrix.ts с
|
||||
* разрешением `read:all` для роли committee/admin.
|
||||
* 2. Новая query `marketplaceListOutgoingPayments` с фильтром
|
||||
* `supplier_account?` (опциональный) под `read:all`.
|
||||
* 3. SDK wrapper Queries.Marketplace.ListOutgoingPayments.
|
||||
*
|
||||
* До этого — страница informational. Совету пока доступны выплаты через
|
||||
* core cassir-стол (общий стол кассира кооператива), который видит всю
|
||||
* историю outgoing payments кооператива.
|
||||
* Эпик 5 / Story 5.x: read-only лента выплат поставщикам по всему кооперативу
|
||||
* для совета. Backend: marketplaceListOutgoingPayments (Payment:read:all) с
|
||||
* опциональными фильтрами по поставщику и статусам. Подтверждение/отказ
|
||||
* выплат делает кассир кооператива — здесь только обзор.
|
||||
*/
|
||||
import type { QTableProps } from 'quasar';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { FailAlert } from 'src/shared/api';
|
||||
import { formatAsset2Digits } from 'src/shared/lib/utils/formatAsset2Digits';
|
||||
import { listOutgoingPayments, type MarketplaceOutgoingPaymentView } from '../api';
|
||||
|
||||
const items = ref<MarketplaceOutgoingPaymentView[]>([]);
|
||||
const loading = ref(false);
|
||||
const supplierFilter = ref<string>('');
|
||||
const statusFilter = ref<string[]>([]);
|
||||
|
||||
const PAYMENT_STATUS_LABEL: Record<string, string> = {
|
||||
PENDING: 'Ожидает оплаты',
|
||||
COMPLETED: 'Оплачено',
|
||||
DECLINED: 'Отклонено',
|
||||
};
|
||||
|
||||
function statusLabel(v: string): string {
|
||||
return PAYMENT_STATUS_LABEL[v] ?? v;
|
||||
}
|
||||
|
||||
const statusOptions = Object.entries(PAYMENT_STATUS_LABEL).map(([value, label]) => ({
|
||||
label,
|
||||
value,
|
||||
}));
|
||||
|
||||
const columns: QTableProps['columns'] = [
|
||||
{ name: 'created_at', label: 'Дата', field: 'created_at', align: 'left', sortable: true, format: formatDate },
|
||||
{ name: 'payee', label: 'Поставщик', field: 'payee_account', align: 'left', sortable: true },
|
||||
{ name: 'amount', label: 'Сумма', field: 'amount', align: 'right', sortable: true, format: (v: string) => formatAsset2Digits(String(v)) },
|
||||
{ name: 'symbol', label: 'Валюта', field: 'symbol', align: 'center' },
|
||||
{ name: 'status', label: 'Статус', field: 'status', align: 'left', sortable: true, format: (v: string) => statusLabel(v) },
|
||||
{ name: 'purpose', label: 'Назначение', field: 'purpose', align: 'left' },
|
||||
];
|
||||
|
||||
const filteredRows = computed(() => {
|
||||
if (!statusFilter.value.length) return items.value;
|
||||
return items.value.filter((r) => statusFilter.value.includes(r.status));
|
||||
});
|
||||
|
||||
const totals = computed(() => {
|
||||
const byStatus: Record<string, number> = {};
|
||||
for (const r of items.value) {
|
||||
byStatus[r.status] = (byStatus[r.status] ?? 0) + 1;
|
||||
}
|
||||
return byStatus;
|
||||
});
|
||||
|
||||
async function load(): Promise<void> {
|
||||
loading.value = true;
|
||||
try {
|
||||
const supplier = supplierFilter.value.trim();
|
||||
items.value = await listOutgoingPayments(
|
||||
supplier ? { supplier_account: supplier } : undefined,
|
||||
);
|
||||
} catch (e) {
|
||||
FailAlert(e, 'Не удалось загрузить ленту выплат');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function formatDate(value: unknown): string {
|
||||
if (value === null || value === undefined) return '—';
|
||||
const parsed = new Date(String(value));
|
||||
return Number.isNaN(parsed.getTime()) ? String(value) : parsed.toLocaleString('ru-RU');
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
void load();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template lang="pug">
|
||||
q-page.mp-role-admin.mp-board-payouts(role="region", aria-label="Выплаты поставщикам — совет")
|
||||
div.text-h5 Выплаты поставщикам — обзор совета
|
||||
q-page.mp-role-admin.mp-board-payouts.q-pa-md(role="region", aria-label="Выплаты поставщикам — совет")
|
||||
.row.items-center.q-mb-xs
|
||||
.text-h5 Выплаты поставщикам — обзор совета
|
||||
q-space
|
||||
q-btn(flat, no-caps, icon="refresh", label="Обновить", :loading="loading", @click="load")
|
||||
.text-caption.text-grey-7.q-mb-md(style="max-width: 720px")
|
||||
| Лента выплат поставщикам по всему кооперативу. Подтверждение и отказ выплат выполняет кассир кооператива — для совета это read-only обзор.
|
||||
|
||||
q-banner.q-mt-md(rounded, class="bg-amber-1 text-amber-9")
|
||||
template(#avatar)
|
||||
q-icon(name="fa-solid fa-screwdriver-wrench", color="amber-9")
|
||||
div.text-subtitle2 Раздел в подготовке
|
||||
div.text-body2
|
||||
| Совет пока не имеет собственного среза по выплатам — текущий backend marketplace отдаёт только историю текущего пользователя как поставщика. Чтобы открыть обзор по всем поставщикам кооператива, нужно расширить marketplace-access-matrix новой politykой
|
||||
strong Payment / read:all
|
||||
| , добавить query
|
||||
strong marketplaceListOutgoingPayments
|
||||
| с опциональным supplier_account и сгенерировать SDK wrapper.
|
||||
div.text-body2.q-mt-sm
|
||||
| До этого — выплаты доступны через
|
||||
strong core cassir-стол
|
||||
| кооператива (общий стол кассира), который видит outgoing-payments всех расширений сразу.
|
||||
|
||||
q-card.q-mt-md(flat, bordered)
|
||||
q-card.mp-card.q-mb-md(flat, bordered)
|
||||
q-card-section
|
||||
div.text-subtitle1 Что увидит совет, когда раздел будет готов
|
||||
ul.q-pl-md
|
||||
li Ленту всех PENDING / CONFIRMED / FAILED / RETRY выплат за период.
|
||||
li Сумму выплаты, поставщика, заказ-источник, дату выплаты.
|
||||
li Фильтр по статусу + per-supplier breakdown.
|
||||
li Read-only — само подтверждение делает кассир, не совет.
|
||||
.row.q-col-gutter-sm.items-end
|
||||
q-input.col-12.col-sm-4(
|
||||
v-model="supplierFilter",
|
||||
label="Поставщик (account)",
|
||||
dense,
|
||||
outlined,
|
||||
clearable,
|
||||
hint="Пусто — все поставщики кооператива",
|
||||
@keyup.enter="load"
|
||||
)
|
||||
q-select.col-12.col-sm-4(
|
||||
v-model="statusFilter",
|
||||
:options="statusOptions",
|
||||
label="Статус выплаты",
|
||||
dense,
|
||||
outlined,
|
||||
multiple,
|
||||
emit-value,
|
||||
map-options
|
||||
)
|
||||
q-btn.col-12.col-sm-3(color="primary", label="Применить", :loading="loading", @click="load")
|
||||
|
||||
q-separator
|
||||
q-card-section
|
||||
div.text-subtitle1 Связанные документы
|
||||
ul.q-pl-md
|
||||
li
|
||||
strong PRD MVP:
|
||||
| /home/admin/blago/production/1-prilozhenie-stol-zakazov/_bmad-output/planning-artifacts/prd.md
|
||||
li
|
||||
strong Резолвер сейчас:
|
||||
| components/controller/src/extensions/marketplace/application/resolvers/marketplace-outgoing-payment.resolver.ts
|
||||
li
|
||||
strong Access matrix:
|
||||
| components/controller/src/extensions/marketplace/application/access/marketplace-access-matrix.ts
|
||||
.row.q-col-gutter-md.q-mb-md(v-if="items.length")
|
||||
q-card.mp-card.col-6.col-sm-3(v-for="(count, status) in totals", :key="status")
|
||||
q-card-section
|
||||
.text-caption.text-grey-7 {{ statusLabel(status) }}
|
||||
.text-h6 {{ count }}
|
||||
|
||||
q-table.mp-card(
|
||||
:rows="filteredRows",
|
||||
:columns="columns",
|
||||
row-key="id",
|
||||
flat,
|
||||
bordered,
|
||||
:loading="loading",
|
||||
:pagination="{ rowsPerPage: 25, sortBy: 'created_at', descending: true }",
|
||||
:rows-per-page-options="[25, 50, 100, 0]",
|
||||
binary-state-sort
|
||||
)
|
||||
template(#body-cell-status="props")
|
||||
q-td(:props="props")
|
||||
span.mp-status-chip {{ statusLabel(props.row.status) }}
|
||||
template(#no-data)
|
||||
.full-width.text-center.q-pa-md.text-grey-7 Выплат по выбранным фильтрам нет.
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.mp-board-payouts {
|
||||
padding: var(--mp-space-lg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--mp-space-md);
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
// Сценарий: Совет открывает informational placeholder для выплат
|
||||
// поставщикам. Эпик 5 / Story 5.x — раздел в подготовке.
|
||||
// Сценарий: совет открывает read-only ленту выплат поставщикам по всему
|
||||
// кооперативу. Backend marketplaceListOutgoingPayments под capability
|
||||
// Payment:read:all (board/board_readonly/admin), опциональный фильтр по
|
||||
// поставщику. Подтверждение/отказ выплат делает кассир кооператива.
|
||||
//
|
||||
// Текущий backend marketplaceListOutgoingPaymentsAsSupplier отдаёт только
|
||||
// выплаты текущего пайщика-supplier'а. Для совета нужна доп. policy
|
||||
// Payment / read:all в marketplace-access-matrix + query
|
||||
// marketplaceListOutgoingPayments с опц. supplier_account. До этого —
|
||||
// placeholder со ссылками на нужные файлы.
|
||||
//
|
||||
// Фикстура: chairman кооператива (ant).
|
||||
// Фикстура: chairman кооператива (ant) — роли admin/board/board_readonly.
|
||||
|
||||
import { loginAsChairman, dismissOnboardingDialogs } from '../../../lib/harness.mjs';
|
||||
import { loginAsChairman, dismissOnboardingDialogs, cleanViteOverlays } from '../../../lib/harness.mjs';
|
||||
|
||||
export const meta = {
|
||||
title: 'Выплаты поставщикам — обзор совета (placeholder)',
|
||||
title: 'Выплаты поставщикам — обзор совета',
|
||||
docPath: 'new/marketplace/board/payouts-readonly.md',
|
||||
assetsDir: 'assets/new/marketplace/board/payouts-readonly',
|
||||
role: 'chairman',
|
||||
@@ -27,12 +23,13 @@ export default async ({ page, context, shot, env }) => {
|
||||
});
|
||||
await page.waitForSelector('text=Выплаты поставщикам', { timeout: 60000 });
|
||||
await page.waitForLoadState('networkidle', { timeout: 15000 }).catch(() => {});
|
||||
await page.waitForTimeout(900);
|
||||
await page.waitForTimeout(1500);
|
||||
await dismissOnboardingDialogs(page);
|
||||
await cleanViteOverlays(page);
|
||||
|
||||
await shot(
|
||||
page,
|
||||
'01-placeholder',
|
||||
'Раздел в подготовке: информационный экран с пояснением, что для совета нужна доп. policy Payment/read:all и query marketplaceListOutgoingPayments. До этого совет видит выплаты через core cassir-стол кооператива. Ссылки на access-matrix и резолвер выплат.',
|
||||
'01-board-payouts',
|
||||
'Лента выплат поставщикам по всему кооперативу для совета: фильтры по поставщику и статусу, сводка-счётчики по статусам и таблица выплат (дата, поставщик, сумма, валюта, статус, назначение). Read-only — подтверждает выплаты кассир кооператива.',
|
||||
);
|
||||
};
|
||||
|
||||
@@ -30,6 +30,8 @@ export * as ListAplReceptionsByBraname from './listAplReceptionsByBraname'
|
||||
export * as ListAplReceptionsAsSupplier from './listAplReceptionsAsSupplier'
|
||||
/** Эпик 5: история выплат поставщика */
|
||||
export * as ListOutgoingPaymentsAsSupplier from './listOutgoingPaymentsAsSupplier'
|
||||
/** Лента выплат поставщикам по кооперативу для совета (Payment:read:all) */
|
||||
export * as ListOutgoingPayments from './listOutgoingPayments'
|
||||
/** Эпик 5: подписные документы Document2 для поставщика (FR45 / 598-15) */
|
||||
export * as AplReceptionSupplierSignablePayloads from './aplReceptionSupplierSignablePayloads'
|
||||
/** Эпик 5: подписные документы Document2 для председателя КУ (FR45 / 598-15) */
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { marketplaceOutgoingPaymentRequestSelector } from '../../selectors/marketplace/outgoingPaymentSelector'
|
||||
import { $, type GraphQLTypes, type InputType, type ModelTypes, Selector } from '../../zeus/index'
|
||||
|
||||
export const name = 'marketplaceListOutgoingPayments'
|
||||
|
||||
export const query = Selector('Query')({
|
||||
[name]: [
|
||||
{
|
||||
supplier_account: $('supplier_account', 'String'),
|
||||
statuses: $('statuses', '[MarketplaceOutgoingPaymentRequestStatus!]'),
|
||||
},
|
||||
marketplaceOutgoingPaymentRequestSelector,
|
||||
],
|
||||
})
|
||||
|
||||
export interface IInput {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
[key: string]: unknown
|
||||
|
||||
supplier_account?: string
|
||||
statuses?: ModelTypes['MarketplaceOutgoingPaymentRequestStatus'][]
|
||||
}
|
||||
|
||||
export type IOutput = InputType<GraphQLTypes['Query'], typeof query>
|
||||
@@ -1979,6 +1979,9 @@ export const AllTypesProps: Record<string,any> = {
|
||||
input:"MarketplaceListOrdersInput",
|
||||
options:"PaginationInput"
|
||||
},
|
||||
marketplaceListOutgoingPayments:{
|
||||
statuses:"MarketplaceOutgoingPaymentRequestStatus"
|
||||
},
|
||||
marketplaceListOutgoingPaymentsAsSupplier:{
|
||||
statuses:"MarketplaceOutgoingPaymentRequestStatus"
|
||||
},
|
||||
@@ -5350,6 +5353,7 @@ export const ReturnTypes: Record<string,any> = {
|
||||
marketplaceListMyOrders:"MarketplaceOrderPaginationResult",
|
||||
marketplaceListMyReadyToReceive:"MarketplaceOrder",
|
||||
marketplaceListMyReturnClaims:"MarketplaceReturnClaim",
|
||||
marketplaceListOutgoingPayments:"MarketplaceOutgoingPaymentRequest",
|
||||
marketplaceListOutgoingPaymentsAsSupplier:"MarketplaceOutgoingPaymentRequest",
|
||||
marketplaceListPendingOffers:"MarketplaceOfferPaginationResult",
|
||||
marketplaceListReturnClaimsByBraname:"MarketplaceReturnClaim",
|
||||
|
||||
@@ -9594,6 +9594,7 @@ 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"]],
|
||||
marketplaceListPendingOffers?: [{ input?: ValueTypes["MarketplaceListPendingOffersInput"] | undefined | null | Variable<any, string>},ValueTypes["MarketplaceOfferPaginationResult"]],
|
||||
marketplaceListReturnClaimsByBraname?: [{ data: ValueTypes["MarketplaceListReturnClaimsByBranameInput"] | Variable<any, string>},ValueTypes["MarketplaceReturnClaim"]],
|
||||
@@ -19448,6 +19449,7 @@ 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"]],
|
||||
marketplaceListPendingOffers?: [{ input?: ResolverInputTypes["MarketplaceListPendingOffersInput"] | undefined | null},ResolverInputTypes["MarketplaceOfferPaginationResult"]],
|
||||
marketplaceListReturnClaimsByBraname?: [{ data: ResolverInputTypes["MarketplaceListReturnClaimsByBranameInput"]},ResolverInputTypes["MarketplaceReturnClaim"]],
|
||||
@@ -29691,6 +29693,8 @@ export type ModelTypes = {
|
||||
marketplaceListMyReadyToReceive: Array<ModelTypes["MarketplaceOrder"]>,
|
||||
/** Все заявления текущего пайщика на гарантийный возврат — активные и архивные. */
|
||||
marketplaceListMyReturnClaims: Array<ModelTypes["MarketplaceReturnClaim"]>,
|
||||
/** Лента выплат поставщикам по всему кооперативу — для совета. Опциональные фильтры: по поставщику-получателю и по статусам. */
|
||||
marketplaceListOutgoingPayments: Array<ModelTypes["MarketplaceOutgoingPaymentRequest"]>,
|
||||
/** История выплат поставщику в столе поставщика — статусы по каждому заказу. */
|
||||
marketplaceListOutgoingPaymentsAsSupplier: Array<ModelTypes["MarketplaceOutgoingPaymentRequest"]>,
|
||||
/** Список Offer'ов на модерации (admin) */
|
||||
@@ -40462,6 +40466,8 @@ export type GraphQLTypes = {
|
||||
marketplaceListMyReadyToReceive: Array<GraphQLTypes["MarketplaceOrder"]>,
|
||||
/** Все заявления текущего пайщика на гарантийный возврат — активные и архивные. */
|
||||
marketplaceListMyReturnClaims: Array<GraphQLTypes["MarketplaceReturnClaim"]>,
|
||||
/** Лента выплат поставщикам по всему кооперативу — для совета. Опциональные фильтры: по поставщику-получателю и по статусам. */
|
||||
marketplaceListOutgoingPayments: Array<GraphQLTypes["MarketplaceOutgoingPaymentRequest"]>,
|
||||
/** История выплат поставщику в столе поставщика — статусы по каждому заказу. */
|
||||
marketplaceListOutgoingPaymentsAsSupplier: Array<GraphQLTypes["MarketplaceOutgoingPaymentRequest"]>,
|
||||
/** Список Offer'ов на модерации (admin) */
|
||||
|
||||
Reference in New Issue
Block a user