Files
fabric_trade_server/dist/shipments/shipments.service.js
T
mohmdsdgandCursor d4aaa8e997 Rebuild order flow: settle after pricing, notifications, and invoice expiry.
Hide prices until admin sends the invoice, enforce status transitions, add customer/admin SMS+in-app notifications, schedule cash invoice reminders, and ship updated dist/prisma-client/deploy-bundle for git-pull deploys.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-09 12:00:13 +03:30

212 lines
8.9 KiB
JavaScript

"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ShipmentsService = void 0;
const common_1 = require("@nestjs/common");
const client_1 = require("@prisma/client");
const prisma_service_1 = require("../prisma/prisma.service");
const name_1 = require("../common/utils/name");
const notifications_service_1 = require("../notifications/notifications.service");
const notification_events_1 = require("../notifications/notification-events");
const STATUS_FLOW = [
client_1.ShipmentStatus.preparing,
client_1.ShipmentStatus.ready,
client_1.ShipmentStatus.shipped,
client_1.ShipmentStatus.delivered,
];
const SHIPMENT_TO_ORDER = {
preparing: client_1.OrderStatus.preparing,
ready: client_1.OrderStatus.ready_to_ship,
shipped: client_1.OrderStatus.shipped,
delivered: client_1.OrderStatus.delivered,
};
let ShipmentsService = class ShipmentsService {
prisma;
notifications;
constructor(prisma, notifications) {
this.prisma = prisma;
this.notifications = notifications;
}
async findAll(status) {
const shipments = await this.prisma.shipment.findMany({
where: status ? { status } : undefined,
orderBy: { createdAt: 'desc' },
include: {
order: { include: { user: true } },
},
});
return shipments.map((s) => this.map(s));
}
async findOne(id) {
const shipment = await this.prisma.shipment.findUnique({
where: { id },
include: { order: { include: { user: true } } },
});
if (!shipment)
throw new common_1.NotFoundException('ارسال یافت نشد');
return this.map(shipment);
}
async create(adminId, dto) {
const order = await this.prisma.order.findUnique({
where: { id: dto.orderId },
include: { shipment: true, user: true },
});
if (!order)
throw new common_1.NotFoundException('سفارش یافت نشد');
if (order.shipment) {
throw new common_1.ConflictException('برای این سفارش قبلاً ارسال ثبت شده است');
}
const status = dto.status ?? client_1.ShipmentStatus.preparing;
const shipment = await this.prisma.$transaction(async (tx) => {
const created = await tx.shipment.create({
data: {
orderId: order.id,
carrier: dto.carrier.trim(),
trackingNumber: dto.trackingNumber?.trim() || null,
meterage: dto.meterage ?? order.totalMeterage,
status,
shippedAt: status === client_1.ShipmentStatus.shipped ? new Date() : null,
deliveredAt: status === client_1.ShipmentStatus.delivered ? new Date() : null,
},
include: { order: { include: { user: true } } },
});
const nextOrderStatus = SHIPMENT_TO_ORDER[status];
if (order.status !== nextOrderStatus) {
await tx.order.update({
where: { id: order.id },
data: { status: nextOrderStatus },
});
await tx.orderStatusHistory.create({
data: {
orderId: order.id,
fromStatus: order.status,
toStatus: nextOrderStatus,
changedBy: `admin:${adminId}`,
note: 'ثبت ارسال',
},
});
}
return created;
});
this.notifyOrderStatus(order.id, SHIPMENT_TO_ORDER[status], {
carrier: shipment.carrier,
trackingNumber: shipment.trackingNumber,
});
return this.map(shipment);
}
async update(id, dto) {
await this.ensure(id);
const shipment = await this.prisma.shipment.update({
where: { id },
data: {
carrier: dto.carrier?.trim(),
trackingNumber: dto.trackingNumber === undefined
? undefined
: dto.trackingNumber?.trim() || null,
meterage: dto.meterage,
status: dto.status,
},
include: { order: { include: { user: true } } },
});
return this.map(shipment);
}
async advanceStatus(id, adminId, dto) {
const shipment = await this.prisma.shipment.findUnique({
where: { id },
include: { order: { include: { user: true } } },
});
if (!shipment)
throw new common_1.NotFoundException('ارسال یافت نشد');
let nextStatus = dto.status;
if (!nextStatus) {
const idx = STATUS_FLOW.indexOf(shipment.status);
if (idx < 0 || idx >= STATUS_FLOW.length - 1) {
throw new common_1.BadRequestException('وضعیت ارسال قابل پیشرفت نیست');
}
nextStatus = STATUS_FLOW[idx + 1];
}
const updated = await this.prisma.$transaction(async (tx) => {
const result = await tx.shipment.update({
where: { id },
data: {
status: nextStatus,
trackingNumber: dto.trackingNumber !== undefined
? dto.trackingNumber.trim() || null
: undefined,
shippedAt: nextStatus === client_1.ShipmentStatus.shipped
? (shipment.shippedAt ?? new Date())
: shipment.shippedAt,
deliveredAt: nextStatus === client_1.ShipmentStatus.delivered
? new Date()
: shipment.deliveredAt,
},
include: { order: { include: { user: true } } },
});
const nextOrderStatus = SHIPMENT_TO_ORDER[nextStatus];
if (shipment.order.status !== nextOrderStatus) {
await tx.order.update({
where: { id: shipment.orderId },
data: { status: nextOrderStatus },
});
await tx.orderStatusHistory.create({
data: {
orderId: shipment.orderId,
fromStatus: shipment.order.status,
toStatus: nextOrderStatus,
changedBy: `admin:${adminId}`,
note: `وضعیت ارسال: ${nextStatus}`,
},
});
}
return result;
});
this.notifyOrderStatus(shipment.orderId, SHIPMENT_TO_ORDER[nextStatus], {
carrier: updated.carrier,
trackingNumber: updated.trackingNumber,
});
return this.map(updated);
}
notifyOrderStatus(orderId, status, context) {
const event = (0, notification_events_1.eventForStatus)(status);
if (event) {
this.notifications.dispatchOrderEvent(orderId, event, context);
}
}
async ensure(id) {
const shipment = await this.prisma.shipment.findUnique({ where: { id } });
if (!shipment)
throw new common_1.NotFoundException('ارسال یافت نشد');
return shipment;
}
map(s) {
return {
id: s.id,
orderId: s.orderId,
orderNumber: s.order.orderNumber,
customerName: (0, name_1.joinFullName)(s.order.user.firstName, s.order.user.lastName),
carrier: s.carrier,
trackingNumber: s.trackingNumber ?? '',
meterage: s.meterage,
status: s.status,
shippedAt: s.shippedAt?.toISOString() ?? null,
deliveredAt: s.deliveredAt?.toISOString() ?? null,
createdAt: s.createdAt.toISOString(),
updatedAt: s.updatedAt.toISOString(),
};
}
};
exports.ShipmentsService = ShipmentsService;
exports.ShipmentsService = ShipmentsService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [prisma_service_1.PrismaService,
notifications_service_1.NotificationsService])
], ShipmentsService);
//# sourceMappingURL=shipments.service.js.map