- Prefijo v2: MCH - TRACEABILITY-MASTER.yml creado - Listo para integracion como submodulo Workspace: v2.0.0 | SIMCO: v4.0.0
193 lines
8.2 KiB
JavaScript
193 lines
8.2 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);
|
|
};
|
|
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.CodiSpeiService = void 0;
|
|
const common_1 = require("@nestjs/common");
|
|
const typeorm_1 = require("@nestjs/typeorm");
|
|
const typeorm_2 = require("typeorm");
|
|
const virtual_account_entity_1 = require("./entities/virtual-account.entity");
|
|
const codi_transaction_entity_1 = require("./entities/codi-transaction.entity");
|
|
const spei_transaction_entity_1 = require("./entities/spei-transaction.entity");
|
|
let CodiSpeiService = class CodiSpeiService {
|
|
constructor(virtualAccountRepo, codiRepo, speiRepo, dataSource) {
|
|
this.virtualAccountRepo = virtualAccountRepo;
|
|
this.codiRepo = codiRepo;
|
|
this.speiRepo = speiRepo;
|
|
this.dataSource = dataSource;
|
|
}
|
|
async getVirtualAccount(tenantId) {
|
|
return this.virtualAccountRepo.findOne({
|
|
where: { tenantId, status: virtual_account_entity_1.VirtualAccountStatus.ACTIVE },
|
|
});
|
|
}
|
|
async createVirtualAccount(tenantId, beneficiaryName, provider = 'stp') {
|
|
const existing = await this.getVirtualAccount(tenantId);
|
|
if (existing) {
|
|
return existing;
|
|
}
|
|
const mockClabe = `646180${Math.floor(Math.random() * 1000000000000).toString().padStart(12, '0')}`;
|
|
const account = this.virtualAccountRepo.create({
|
|
tenantId,
|
|
provider,
|
|
clabe: mockClabe,
|
|
beneficiaryName,
|
|
status: virtual_account_entity_1.VirtualAccountStatus.ACTIVE,
|
|
});
|
|
return this.virtualAccountRepo.save(account);
|
|
}
|
|
async generateQr(tenantId, dto) {
|
|
const result = await this.dataSource.query(`SELECT generate_codi_reference($1) as reference`, [tenantId]);
|
|
const reference = result[0].reference;
|
|
const expiresAt = new Date();
|
|
expiresAt.setMinutes(expiresAt.getMinutes() + 5);
|
|
const qrData = JSON.stringify({
|
|
type: 'codi',
|
|
amount: dto.amount,
|
|
reference,
|
|
merchant: tenantId,
|
|
expires: expiresAt.toISOString(),
|
|
});
|
|
const transaction = this.codiRepo.create({
|
|
tenantId,
|
|
saleId: dto.saleId,
|
|
qrData,
|
|
amount: dto.amount,
|
|
reference,
|
|
description: dto.description || `Cobro ${reference}`,
|
|
status: codi_transaction_entity_1.CodiTransactionStatus.PENDING,
|
|
expiresAt,
|
|
});
|
|
return this.codiRepo.save(transaction);
|
|
}
|
|
async getCodiStatus(id) {
|
|
const transaction = await this.codiRepo.findOne({ where: { id } });
|
|
if (!transaction) {
|
|
throw new common_1.NotFoundException('Transaccion CoDi no encontrada');
|
|
}
|
|
if (transaction.status === codi_transaction_entity_1.CodiTransactionStatus.PENDING &&
|
|
new Date() > transaction.expiresAt) {
|
|
transaction.status = codi_transaction_entity_1.CodiTransactionStatus.EXPIRED;
|
|
await this.codiRepo.save(transaction);
|
|
}
|
|
return transaction;
|
|
}
|
|
async confirmCodi(id, providerData) {
|
|
const transaction = await this.getCodiStatus(id);
|
|
if (transaction.status !== codi_transaction_entity_1.CodiTransactionStatus.PENDING) {
|
|
throw new common_1.BadRequestException(`Transaccion no esta pendiente: ${transaction.status}`);
|
|
}
|
|
transaction.status = codi_transaction_entity_1.CodiTransactionStatus.CONFIRMED;
|
|
transaction.confirmedAt = new Date();
|
|
transaction.providerResponse = providerData;
|
|
return this.codiRepo.save(transaction);
|
|
}
|
|
async getCodiTransactions(tenantId, limit = 50) {
|
|
return this.codiRepo.find({
|
|
where: { tenantId },
|
|
order: { createdAt: 'DESC' },
|
|
take: limit,
|
|
});
|
|
}
|
|
async getSpeiTransactions(tenantId, limit = 50) {
|
|
return this.speiRepo.find({
|
|
where: { tenantId },
|
|
order: { receivedAt: 'DESC' },
|
|
take: limit,
|
|
});
|
|
}
|
|
async receiveSpei(tenantId, data) {
|
|
const account = await this.getVirtualAccount(tenantId);
|
|
const transaction = this.speiRepo.create({
|
|
tenantId,
|
|
virtualAccountId: account?.id,
|
|
amount: data.amount,
|
|
senderClabe: data.senderClabe,
|
|
senderName: data.senderName,
|
|
senderRfc: data.senderRfc,
|
|
senderBank: data.senderBank,
|
|
reference: data.reference,
|
|
trackingKey: data.trackingKey,
|
|
status: spei_transaction_entity_1.SpeiTransactionStatus.RECEIVED,
|
|
receivedAt: new Date(),
|
|
providerData: data.providerData,
|
|
});
|
|
return this.speiRepo.save(transaction);
|
|
}
|
|
async reconcileSpei(id, saleId) {
|
|
const transaction = await this.speiRepo.findOne({ where: { id } });
|
|
if (!transaction) {
|
|
throw new common_1.NotFoundException('Transaccion SPEI no encontrada');
|
|
}
|
|
transaction.saleId = saleId;
|
|
transaction.status = spei_transaction_entity_1.SpeiTransactionStatus.RECONCILED;
|
|
transaction.reconciledAt = new Date();
|
|
return this.speiRepo.save(transaction);
|
|
}
|
|
async getSummary(tenantId, date) {
|
|
const targetDate = date || new Date();
|
|
const dateStr = targetDate.toISOString().split('T')[0];
|
|
const result = await this.dataSource.query(`SELECT * FROM get_codi_spei_summary($1, $2::date)`, [tenantId, dateStr]);
|
|
return result[0] || {
|
|
codi_count: 0,
|
|
codi_total: 0,
|
|
spei_count: 0,
|
|
spei_total: 0,
|
|
};
|
|
}
|
|
async handleCodiWebhook(payload) {
|
|
const { reference, status, transactionId } = payload;
|
|
const transaction = await this.codiRepo.findOne({
|
|
where: { reference },
|
|
});
|
|
if (!transaction) {
|
|
throw new common_1.NotFoundException('Transaccion no encontrada');
|
|
}
|
|
if (status === 'confirmed') {
|
|
await this.confirmCodi(transaction.id, {
|
|
providerTransactionId: transactionId,
|
|
...payload,
|
|
});
|
|
}
|
|
}
|
|
async handleSpeiWebhook(clabe, payload) {
|
|
const account = await this.virtualAccountRepo.findOne({
|
|
where: { clabe },
|
|
});
|
|
if (!account) {
|
|
throw new common_1.NotFoundException('Cuenta virtual no encontrada');
|
|
}
|
|
await this.receiveSpei(account.tenantId, {
|
|
amount: payload.amount,
|
|
senderClabe: payload.senderClabe,
|
|
senderName: payload.senderName,
|
|
senderRfc: payload.senderRfc,
|
|
senderBank: payload.senderBank,
|
|
reference: payload.reference,
|
|
trackingKey: payload.trackingKey,
|
|
providerData: payload,
|
|
});
|
|
}
|
|
};
|
|
exports.CodiSpeiService = CodiSpeiService;
|
|
exports.CodiSpeiService = CodiSpeiService = __decorate([
|
|
(0, common_1.Injectable)(),
|
|
__param(0, (0, typeorm_1.InjectRepository)(virtual_account_entity_1.VirtualAccount)),
|
|
__param(1, (0, typeorm_1.InjectRepository)(codi_transaction_entity_1.CodiTransaction)),
|
|
__param(2, (0, typeorm_1.InjectRepository)(spei_transaction_entity_1.SpeiTransaction)),
|
|
__metadata("design:paramtypes", [typeorm_2.Repository,
|
|
typeorm_2.Repository,
|
|
typeorm_2.Repository,
|
|
typeorm_2.DataSource])
|
|
], CodiSpeiService);
|
|
//# sourceMappingURL=codi-spei.service.js.map
|