diff --git a/apps/api/src/pipelines/deals.service.ts b/apps/api/src/pipelines/deals.service.ts
index 0328ec2..d153853 100644
--- a/apps/api/src/pipelines/deals.service.ts
+++ b/apps/api/src/pipelines/deals.service.ts
@@ -225,14 +225,15 @@ export class DealsService {
}
const data: Prisma.DealUncheckedUpdateInput = {};
+ const pricedFromLines = (dto.lineItems?.length ?? 0) > 0;
if (dto.title !== undefined) data.title = dto.title.trim();
- if ('amount' in dto && dto.lineItems === undefined) {
+ if ('amount' in dto && !pricedFromLines) {
data.amount =
dto.amount == null || Number.isNaN(Number(dto.amount))
? null
: new Prisma.Decimal(dto.amount);
}
- if (dto.currency !== undefined && dto.lineItems === undefined) {
+ if (dto.currency !== undefined && !pricedFromLines) {
data.currency = dto.currency.trim() || 'IRR';
}
if ('source' in dto) data.source = emptyToNull(dto.source);
@@ -270,7 +271,7 @@ export class DealsService {
assigneeConnect = assigneeIds.map((uid) => ({ id: uid }));
}
- if (dto.lineItems !== undefined) {
+ if (pricedFromLines && dto.lineItems) {
const total = sumLineItems(dto.lineItems);
data.amount =
total == null ? null : new Prisma.Decimal(total);
diff --git a/apps/web/src/components/gamification/ClubLeaderboard.vue b/apps/web/src/components/gamification/ClubLeaderboard.vue
index 723686f..3d3e700 100644
--- a/apps/web/src/components/gamification/ClubLeaderboard.vue
+++ b/apps/web/src/components/gamification/ClubLeaderboard.vue
@@ -97,26 +97,26 @@ const meOutside = computed(() => {
-
+ {{ toFaDigits(e.rank) }}
+
+ {{ e.isMe ? 'شما' : e.fullName }}
+ {{ faNum(e.score) }}
{{ e.change > 0 ? '▲' : '▼' }} {{ toFaDigits(Math.abs(e.change)) }}
- {{ faNum(e.score) }}
- {{ e.isMe ? 'شما' : e.fullName }}
-
- {{ toFaDigits(e.rank) }}
- ⋯
-
+ {{ toFaDigits(meOutside.rank) }}
+
+ شما
+ {{ faNum(meOutside.score) }}
{{ meOutside.change > 0 ? '▲' : '▼' }} {{ toFaDigits(Math.abs(meOutside.change)) }}
- {{ faNum(meOutside.score) }}
- شما
-
- {{ toFaDigits(meOutside.rank) }}
- هنوز کسی در این بازه امتیاز نگرفته است.
@@ -315,7 +315,7 @@ const meOutside = computed(() => {
.who {
flex: 1;
min-width: 0;
- text-align: end;
+ text-align: start;
font-size: 0.84rem;
font-weight: 600;
color: #0f172a;
diff --git a/apps/web/src/views/DealFormView.vue b/apps/web/src/views/DealFormView.vue
index 3fa93f8..8579c23 100644
--- a/apps/web/src/views/DealFormView.vue
+++ b/apps/web/src/views/DealFormView.vue
@@ -116,6 +116,8 @@ const sourceRef = ref('');
const status = ref('');
const customFields = ref>({});
const lines = ref([]);
+/** تعداد اقلام ذخیرهشده؛ برای حذف همهٔ اقلام باید آرایهٔ خالی فرستاده شود */
+const savedLineCount = ref(0);
const nextDueDate = ref('');
const nextDueTime = ref('10:30');
@@ -364,7 +366,11 @@ async function load() {
quantity: String(item.quantity),
unitPrice: String(item.unitPrice),
}));
+ savedLineCount.value = lines.value.length;
productsOpen.value = lines.value.length > 0;
+ if (data.company && !companies.value.some((c) => c.id === data.company!.id)) {
+ companies.value = [{ id: data.company.id, name: data.company.name } as CompanyDto, ...companies.value];
+ }
if (data.pipelineId !== pipelineId.value) {
await loadBoard(data.pipelineId);
stageId.value = data.stageId;
@@ -397,6 +403,7 @@ async function load() {
function payload(): CreateDealRequest {
const lineItems = toLineInputs();
+ const sendLineItems = lineItems.length > 0 || savedLineCount.value > 0;
return {
title: title.value,
amount:
@@ -423,12 +430,12 @@ function payload(): CreateDealRequest {
stageId: stageId.value || undefined,
customFields: customFields.value,
currency: currency.value || 'IRR',
- lineItems,
+ ...(sendLineItems ? { lineItems } : {}),
};
}
async function createFollowUp(dealId: string) {
- if (!isNew.value || !nextDueDate.value) return;
+ if (!nextDueDate.value) return;
const due = new Date(`${nextDueDate.value}T${nextDueTime.value || '10:30'}:00`);
if (Number.isNaN(due.getTime())) return;
await api.post('/activities', {
@@ -488,6 +495,11 @@ async function submit() {
if (moveStageId) {
await api.patch(`/deals/${id.value}/move`, { stageId: moveStageId });
}
+ try {
+ await createFollowUp(id.value);
+ } catch {
+ /* deal saved; follow-up is optional */
+ }
if (props.embedded) {
emit('saved');
return;