geek-custom-api-core 0.0.47 → 0.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.history/package_20260221164010.json +97 -0
- package/.history/package_20260221164247.json +98 -0
- package/.history/package_20260228094315.json +99 -0
- package/.history/sql/deposit_20260221172413.sql +136 -0
- package/.history/sql/deposit_20260221172422.sql +136 -0
- package/.history/sql/deposit_20260221172436.sql +136 -0
- package/.history/sql/deposit_20260221172455.sql +136 -0
- package/.history/sql/deposit_20260221172502.sql +136 -0
- package/.history/sql/deposit_20260221172519.sql +136 -0
- package/.history/sql/deposit_20260221172816.sql +141 -0
- package/.history/sql/deposit_20260221172832.sql +141 -0
- package/.history/sql/deposit_20260221172911.sql +140 -0
- package/.history/sql/deposit_20260221175833.sql +141 -0
- package/.history/sql/deposit_20260221223728.sql +141 -0
- package/dist/api/app/deposit/deposit.admin.controller.d.ts +33 -2
- package/dist/api/app/deposit/deposit.admin.controller.js +135 -36
- package/dist/api/app/deposit/deposit.admin.controller.js.map +1 -1
- package/dist/api/app/deposit/deposit.service.d.ts +39 -4
- package/dist/api/app/deposit/deposit.service.js +335 -170
- package/dist/api/app/deposit/deposit.service.js.map +1 -1
- package/dist/api/app/deposit/dto/depositJobSearch.dto.d.ts +8 -0
- package/dist/api/app/deposit/dto/depositJobSearch.dto.js +53 -0
- package/dist/api/app/deposit/dto/depositJobSearch.dto.js.map +1 -0
- package/dist/api/app/deposit/entity/depositJobResult.entity.d.ts +12 -0
- package/dist/api/app/deposit/entity/depositJobResult.entity.js +72 -0
- package/dist/api/app/deposit/entity/depositJobResult.entity.js.map +1 -0
- package/dist/common/config/orm.config.js +1 -1
- package/dist/common/config/orm.config.js.map +1 -1
- package/dist/common/util/gsUtil.js +3 -0
- package/dist/common/util/gsUtil.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -2
- package/sql/deposit.sql +24 -8
|
@@ -41,6 +41,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
41
41
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
42
42
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
43
43
|
};
|
|
44
|
+
var DepositService_1;
|
|
44
45
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
46
|
exports.DepositService = void 0;
|
|
46
47
|
const common_1 = require("@nestjs/common");
|
|
@@ -48,6 +49,7 @@ const default_service_1 = require("../../../common/service/default.service");
|
|
|
48
49
|
const depositJob_entity_1 = require("./entity/depositJob.entity");
|
|
49
50
|
const enum_1 = require("../../../common/enum/enum");
|
|
50
51
|
const depositJobDetail_entity_1 = require("./entity/depositJobDetail.entity");
|
|
52
|
+
const depositJobResult_entity_1 = require("./entity/depositJobResult.entity");
|
|
51
53
|
const XLSX = __importStar(require("xlsx"));
|
|
52
54
|
const depositManager_entity_1 = require("./entity/depositManager.entity");
|
|
53
55
|
const gsUtil_1 = require("../../../common/util/gsUtil");
|
|
@@ -59,70 +61,136 @@ const partner_service_1 = require("../../admin/partner/partner.service");
|
|
|
59
61
|
const core_1 = require("@nestjs/core");
|
|
60
62
|
const date_fns_1 = require("date-fns");
|
|
61
63
|
const depositOrder_entity_1 = require("./entity/depositOrder.entity");
|
|
62
|
-
let DepositService = class DepositService extends default_service_1.DefaultService {
|
|
64
|
+
let DepositService = DepositService_1 = class DepositService extends default_service_1.DefaultService {
|
|
63
65
|
constructor(partnerService, moduleRef) {
|
|
64
66
|
super(moduleRef);
|
|
65
67
|
this.partnerService = partnerService;
|
|
66
68
|
this.moduleRef = moduleRef;
|
|
69
|
+
this.logger = new common_1.Logger(DepositService_1.name);
|
|
67
70
|
}
|
|
68
71
|
async issueSingle(dto) {
|
|
69
|
-
|
|
70
|
-
throw new common_1.HttpException('예치금 금액은 0보다 큰 값이어야 합니다.', common_1.HttpStatus.BAD_REQUEST);
|
|
71
|
-
}
|
|
72
|
-
if (dto.expiredDt && dto.expiredDt < new Date()) {
|
|
73
|
-
throw new common_1.HttpException('만료일시는 현재 시간 이후여야 합니다.', common_1.HttpStatus.BAD_REQUEST);
|
|
74
|
-
}
|
|
72
|
+
const targetAmount = Number(dto.amount);
|
|
75
73
|
const entityManager = await this.getEntityManager();
|
|
76
|
-
entityManager.transaction(async (manager) => {
|
|
77
|
-
|
|
74
|
+
return await entityManager.transaction(async (manager) => {
|
|
75
|
+
const partner = await this.partnerService.findOne(dto.partnerSno);
|
|
76
|
+
const member = await (0, gsUtil_1.shopByServerApi)('/profile', enum_1.HTTP_METHOD.GET, partner.systemKey, partner.longLivedToken, { memberNo: dto.memberNo });
|
|
77
|
+
if (!member) {
|
|
78
|
+
throw new Error('존재하지 않는 회원');
|
|
79
|
+
}
|
|
80
|
+
const memberId = member.memberId;
|
|
81
|
+
const memberName = member.memberName;
|
|
78
82
|
const job = await manager.save(depositJob_entity_1.DepositJob, {
|
|
79
83
|
managerSno: dto.managerSno,
|
|
80
84
|
jobType: enum_1.DEPOSIT_JOB_TYPE.SINGLE,
|
|
85
|
+
jobName: targetAmount > 0 ? '단건 지급' : '단건 차감',
|
|
81
86
|
totalCount: 1,
|
|
82
|
-
successCount:
|
|
87
|
+
successCount: 1,
|
|
83
88
|
failCount: 0,
|
|
84
89
|
status: enum_1.DEPOSIT_STATUS.DONE,
|
|
85
90
|
});
|
|
86
|
-
|
|
87
|
-
jobSno: job.sno,
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
memberId:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
91
|
+
if (targetAmount > 0) {
|
|
92
|
+
return await this.processIssue(manager, Object.assign(Object.assign({}, dto), { memberId: member.memberId, memberName: member.memberName, jobSno: job.sno, amount: targetAmount }));
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
return await this.executeFifoDeduct(manager, Object.assign(Object.assign({}, dto), { memberId: member.memberId, memberName: member.memberName, amount: Math.abs(targetAmount), orderNo: `DEDUCT_SINGLE_${Date.now()}` }));
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
async executeFifoDeduct(manager, data) {
|
|
100
|
+
const deductOrder = await manager.save(depositOrder_entity_1.DepositOrder, {
|
|
101
|
+
partnerSno: data.partnerSno,
|
|
102
|
+
memberNo: data.memberNo,
|
|
103
|
+
orderNo: data.orderNo,
|
|
104
|
+
memberId: data.memberId,
|
|
105
|
+
memberName: data.memberName,
|
|
106
|
+
usedAmount: data.amount,
|
|
107
|
+
orderStatus: 'DONE',
|
|
108
|
+
});
|
|
109
|
+
const availableIssues = await manager.query(`
|
|
110
|
+
SELECT jd.sno AS issueDetailSno, jd.depositAmount, jd.expiredDt,
|
|
111
|
+
(jd.depositAmount - IFNULL(usedSub.netUsed, 0)) AS remainAmount
|
|
112
|
+
FROM gs_depositJobDetail jd
|
|
113
|
+
LEFT JOIN (
|
|
114
|
+
SELECT issueDetailSno, SUM(usedDepositAmount - refundAmount) AS netUsed
|
|
115
|
+
FROM gs_depositOrderDetail GROUP BY issueDetailSno
|
|
116
|
+
) usedSub ON jd.sno = usedSub.issueDetailSno
|
|
117
|
+
WHERE jd.partnerSno = ? AND jd.memberNo = ? AND jd.expireFl = 'N'
|
|
118
|
+
AND (jd.expiredDt IS NULL OR jd.expiredDt >= NOW())
|
|
119
|
+
HAVING remainAmount > 0
|
|
120
|
+
ORDER BY CASE WHEN jd.expiredDt IS NULL THEN 1 ELSE 0 END ASC, jd.expiredDt ASC, jd.sno ASC
|
|
121
|
+
FOR UPDATE
|
|
122
|
+
`, [data.partnerSno, data.memberNo]);
|
|
123
|
+
let remainToDeduct = data.amount;
|
|
124
|
+
const details = [];
|
|
125
|
+
for (const issue of availableIssues) {
|
|
126
|
+
if (remainToDeduct <= 0)
|
|
127
|
+
break;
|
|
128
|
+
const take = Math.min(Number(issue.remainAmount), remainToDeduct);
|
|
129
|
+
details.push(manager.create(depositOrderDetail_entity_1.DepositOrderDetail, {
|
|
130
|
+
orderSno: deductOrder.sno,
|
|
131
|
+
partnerSno: data.partnerSno,
|
|
132
|
+
memberNo: data.memberNo,
|
|
133
|
+
orderProductOptionNo: 'DEDUCT',
|
|
134
|
+
mallProductNo: 'DEDUCT',
|
|
135
|
+
orderProductName: `[관리자차감] ${data.reason}`,
|
|
136
|
+
usedDepositAmount: take,
|
|
137
|
+
issueDetailSno: issue.issueDetailSno,
|
|
138
|
+
refundYn: enum_1.YN.N,
|
|
139
|
+
}));
|
|
140
|
+
remainToDeduct -= take;
|
|
141
|
+
}
|
|
142
|
+
if (remainToDeduct > 0)
|
|
143
|
+
throw new Error(`잔액 부족 (부족분: ${remainToDeduct})`);
|
|
144
|
+
await manager.save(depositOrderDetail_entity_1.DepositOrderDetail, details);
|
|
145
|
+
const [lastLedger] = await manager.query(`SELECT balanceAfter FROM gs_depositManager WHERE partnerSno = ? AND memberNo = ? ORDER BY sno DESC LIMIT 1 FOR UPDATE`, [data.partnerSno, data.memberNo]);
|
|
146
|
+
const prevBalance = Number((lastLedger === null || lastLedger === void 0 ? void 0 : lastLedger.balanceAfter) || 0);
|
|
147
|
+
await manager.save(depositManager_entity_1.DepositManager, {
|
|
148
|
+
partnerSno: data.partnerSno,
|
|
149
|
+
memberNo: data.memberNo,
|
|
150
|
+
memberId: data.memberId,
|
|
151
|
+
memberName: data.memberName,
|
|
152
|
+
depositType: enum_1.DEPOSIT_TYPE.ADJUST,
|
|
153
|
+
source: enum_1.DEPOSIT_SOURCE.ADMIN,
|
|
154
|
+
refType: enum_1.DEPOSIT_REF_TYPE.ORDER,
|
|
155
|
+
refSno: deductOrder.sno,
|
|
156
|
+
depositAmount: -data.amount,
|
|
157
|
+
balanceAfter: prevBalance - data.amount,
|
|
158
|
+
reason: data.reason,
|
|
159
|
+
managerSno: data.managerSno,
|
|
125
160
|
});
|
|
161
|
+
return { success: true };
|
|
162
|
+
}
|
|
163
|
+
async processIssue(manager, data) {
|
|
164
|
+
var _a;
|
|
165
|
+
const jobDetail = await manager.save(depositJobDetail_entity_1.DepositJobDetail, {
|
|
166
|
+
jobSno: data.jobSno,
|
|
167
|
+
partnerSno: data.partnerSno,
|
|
168
|
+
memberNo: data.memberNo,
|
|
169
|
+
memberId: data.memberId,
|
|
170
|
+
memberName: data.memberName,
|
|
171
|
+
depositAmount: data.amount,
|
|
172
|
+
reason: data.reason,
|
|
173
|
+
expiredDt: data.expiredDt || null,
|
|
174
|
+
});
|
|
175
|
+
const [lastLedger] = await manager.query(`SELECT balanceAfter FROM gs_depositManager
|
|
176
|
+
WHERE partnerSno = ? AND memberNo = ?
|
|
177
|
+
ORDER BY sno DESC LIMIT 1 FOR UPDATE`, [data.partnerSno, data.memberNo]);
|
|
178
|
+
const prevBalance = Number((_a = lastLedger === null || lastLedger === void 0 ? void 0 : lastLedger.balanceAfter) !== null && _a !== void 0 ? _a : 0);
|
|
179
|
+
await manager.save(depositManager_entity_1.DepositManager, {
|
|
180
|
+
partnerSno: data.partnerSno,
|
|
181
|
+
memberNo: data.memberNo,
|
|
182
|
+
memberId: data.memberId,
|
|
183
|
+
memberName: data.memberName,
|
|
184
|
+
depositType: enum_1.DEPOSIT_TYPE.ISSUE,
|
|
185
|
+
source: enum_1.DEPOSIT_SOURCE.ADMIN,
|
|
186
|
+
managerSno: data.managerSno,
|
|
187
|
+
refType: enum_1.DEPOSIT_REF_TYPE.JOB_DETAIL,
|
|
188
|
+
refSno: jobDetail.sno,
|
|
189
|
+
depositAmount: data.amount,
|
|
190
|
+
balanceAfter: prevBalance + data.amount,
|
|
191
|
+
reason: data.reason,
|
|
192
|
+
});
|
|
193
|
+
return { success: true, jobDetailSno: jobDetail.sno };
|
|
126
194
|
}
|
|
127
195
|
async issueByExcel(file, managerSno, partnerSno, jobName) {
|
|
128
196
|
const workbook = XLSX.read(file.buffer, { type: 'buffer' });
|
|
@@ -133,146 +201,221 @@ let DepositService = class DepositService extends default_service_1.DefaultServi
|
|
|
133
201
|
}
|
|
134
202
|
const entityManager = await this.getEntityManager();
|
|
135
203
|
const job = await entityManager.save(depositJob_entity_1.DepositJob, {
|
|
136
|
-
managerSno
|
|
204
|
+
managerSno,
|
|
137
205
|
jobType: enum_1.DEPOSIT_JOB_TYPE.EXCEL,
|
|
138
|
-
jobName
|
|
139
|
-
totalCount: rows.length,
|
|
206
|
+
jobName,
|
|
207
|
+
totalCount: rows.length - 1,
|
|
140
208
|
successCount: 0,
|
|
141
209
|
failCount: 0,
|
|
142
210
|
status: enum_1.DEPOSIT_STATUS.PROCESSING,
|
|
143
211
|
});
|
|
212
|
+
this.processExcelJobAsync(rows, job.sno, managerSno, partnerSno).catch((err) => this.logger.error(`Excel job ${job.sno} failed unexpectedly: ${err.message}`, err.stack));
|
|
213
|
+
return {
|
|
214
|
+
jobSno: job.sno,
|
|
215
|
+
totalCount: rows.length - 1,
|
|
216
|
+
status: enum_1.DEPOSIT_STATUS.PROCESSING,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
async processExcelJobAsync(rows, jobSno, managerSno, partnerSno) {
|
|
220
|
+
const entityManager = await this.getEntityManager();
|
|
221
|
+
const partner = await this.partnerService.findOne(partnerSno);
|
|
144
222
|
let successCount = 0;
|
|
145
223
|
let failCount = 0;
|
|
146
|
-
const results = [];
|
|
147
|
-
const partner = await this.partnerService.findOne(partnerSno);
|
|
148
224
|
for (const [index, row] of rows.entries()) {
|
|
225
|
+
if (index === 0)
|
|
226
|
+
continue;
|
|
227
|
+
const memberNo = row.memberNo ? Number(row.memberNo) : 0;
|
|
228
|
+
const amount = Number(row.amount || 0);
|
|
229
|
+
const member = await (0, gsUtil_1.shopByServerApi)('/profile', enum_1.HTTP_METHOD.GET, partner.systemKey, partner.longLivedToken, { memberNo: memberNo });
|
|
230
|
+
if (!member) {
|
|
231
|
+
throw new Error('존재하지 않는 회원');
|
|
232
|
+
}
|
|
233
|
+
const memberId = member.memberId;
|
|
234
|
+
const memberName = member.memberName;
|
|
149
235
|
try {
|
|
150
|
-
if (index === 0) {
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
236
|
await this.issueSingleRow({
|
|
154
237
|
row,
|
|
155
|
-
jobSno
|
|
238
|
+
jobSno,
|
|
156
239
|
managerSno,
|
|
157
240
|
partnerSno,
|
|
158
241
|
systemKey: partner.systemKey,
|
|
159
242
|
longLivedToken: partner.longLivedToken,
|
|
160
243
|
});
|
|
161
244
|
successCount++;
|
|
162
|
-
|
|
245
|
+
await entityManager.save(depositJobResult_entity_1.DepositJobResult, {
|
|
246
|
+
jobSno,
|
|
247
|
+
partnerSno,
|
|
248
|
+
memberNo,
|
|
249
|
+
memberId,
|
|
250
|
+
memberName,
|
|
251
|
+
depositAmount: amount,
|
|
252
|
+
status: enum_1.DEPOSIT_RESULT.SUCCESS,
|
|
253
|
+
reason: row.reason || '',
|
|
254
|
+
});
|
|
163
255
|
}
|
|
164
256
|
catch (e) {
|
|
165
257
|
failCount++;
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
258
|
+
await entityManager.save(depositJobResult_entity_1.DepositJobResult, {
|
|
259
|
+
jobSno,
|
|
260
|
+
partnerSno,
|
|
261
|
+
memberNo,
|
|
262
|
+
memberId,
|
|
263
|
+
memberName,
|
|
264
|
+
depositAmount: amount,
|
|
265
|
+
status: enum_1.DEPOSIT_RESULT.FAIL,
|
|
266
|
+
reason: e.message || '알 수 없는 오류',
|
|
170
267
|
});
|
|
171
268
|
}
|
|
172
269
|
}
|
|
173
|
-
await entityManager.update(depositJob_entity_1.DepositJob,
|
|
270
|
+
await entityManager.update(depositJob_entity_1.DepositJob, jobSno, {
|
|
174
271
|
successCount,
|
|
175
272
|
failCount,
|
|
176
273
|
status: enum_1.DEPOSIT_STATUS.DONE,
|
|
177
274
|
});
|
|
275
|
+
}
|
|
276
|
+
async getJobList(dto) {
|
|
277
|
+
const entityManager = await this.getEntityManager();
|
|
278
|
+
const qb = entityManager.createQueryBuilder(depositJob_entity_1.DepositJob, 'j');
|
|
279
|
+
qb.andWhere('j.managerSno IN (SELECT sno FROM gs_manager WHERE partnerSno = :partnerSno)', {
|
|
280
|
+
partnerSno: dto.partnerSno,
|
|
281
|
+
});
|
|
282
|
+
if (dto.jobName) {
|
|
283
|
+
qb.andWhere('j.jobName LIKE :jobName', {
|
|
284
|
+
jobName: `%${dto.jobName}%`,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
if (dto.jobType) {
|
|
288
|
+
qb.andWhere('j.jobType = :jobType', { jobType: dto.jobType });
|
|
289
|
+
}
|
|
290
|
+
if (dto.status) {
|
|
291
|
+
qb.andWhere('j.status = :status', { status: dto.status });
|
|
292
|
+
}
|
|
293
|
+
qb.select(['j.*']);
|
|
294
|
+
qb.orderBy('j.regDt', 'DESC');
|
|
295
|
+
qb.offset(dto.skip);
|
|
296
|
+
qb.limit(dto.take);
|
|
297
|
+
const list = await qb.getRawMany();
|
|
298
|
+
const count = await qb.getCount();
|
|
299
|
+
return (0, gsUtil_1.paginateResponse)([list, count], dto.page, dto.take);
|
|
300
|
+
}
|
|
301
|
+
async getJobResultList(jobSno, dto) {
|
|
302
|
+
const entityManager = await this.getEntityManager();
|
|
303
|
+
const qb = entityManager.createQueryBuilder(depositJobResult_entity_1.DepositJobResult, 'jr');
|
|
304
|
+
qb.andWhere('jr.jobSno = :jobSno', { jobSno });
|
|
305
|
+
qb.select(['jr.*']);
|
|
306
|
+
qb.orderBy('jr.sno', 'ASC');
|
|
307
|
+
qb.offset(dto.skip);
|
|
308
|
+
qb.limit(dto.take);
|
|
309
|
+
const list = await qb.getRawMany();
|
|
310
|
+
const count = await qb.getCount();
|
|
311
|
+
return (0, gsUtil_1.paginateResponse)([list, count], dto.page, dto.take);
|
|
312
|
+
}
|
|
313
|
+
async getJobStatus(jobSno, partnerSno) {
|
|
314
|
+
const entityManager = await this.getEntityManager();
|
|
315
|
+
const job = await entityManager.findOne(depositJob_entity_1.DepositJob, {
|
|
316
|
+
where: { sno: jobSno },
|
|
317
|
+
});
|
|
318
|
+
if (!job) {
|
|
319
|
+
throw new common_1.HttpException('작업을 찾을 수 없습니다.', common_1.HttpStatus.NOT_FOUND);
|
|
320
|
+
}
|
|
178
321
|
return {
|
|
179
322
|
jobSno: job.sno,
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
323
|
+
jobName: job.jobName,
|
|
324
|
+
totalCount: job.totalCount,
|
|
325
|
+
successCount: job.successCount,
|
|
326
|
+
failCount: job.failCount,
|
|
327
|
+
status: job.status,
|
|
184
328
|
};
|
|
185
329
|
}
|
|
330
|
+
async getJobResultExcel(jobSno, partnerSno) {
|
|
331
|
+
const entityManager = await this.getEntityManager();
|
|
332
|
+
const job = await entityManager.findOne(depositJob_entity_1.DepositJob, {
|
|
333
|
+
where: { sno: jobSno },
|
|
334
|
+
});
|
|
335
|
+
if (!job) {
|
|
336
|
+
throw new common_1.HttpException('작업을 찾을 수 없습니다.', common_1.HttpStatus.NOT_FOUND);
|
|
337
|
+
}
|
|
338
|
+
if (job.status !== enum_1.DEPOSIT_STATUS.DONE) {
|
|
339
|
+
throw new common_1.HttpException('작업이 아직 진행 중입니다.', common_1.HttpStatus.BAD_REQUEST);
|
|
340
|
+
}
|
|
341
|
+
const results = await entityManager.find(depositJobResult_entity_1.DepositJobResult, {
|
|
342
|
+
where: { jobSno },
|
|
343
|
+
order: { sno: 'ASC' },
|
|
344
|
+
});
|
|
345
|
+
const excelData = results.map((r) => ({
|
|
346
|
+
회원번호: r.memberNo,
|
|
347
|
+
회원아이디: r.memberId || '',
|
|
348
|
+
회원명: r.memberName || '',
|
|
349
|
+
금액: r.depositAmount,
|
|
350
|
+
처리결과: r.status === enum_1.DEPOSIT_RESULT.SUCCESS ? '성공' : '실패',
|
|
351
|
+
실패사유: r.status === enum_1.DEPOSIT_RESULT.FAIL ? r.reason : '',
|
|
352
|
+
}));
|
|
353
|
+
const workbook = XLSX.utils.book_new();
|
|
354
|
+
const sheet = XLSX.utils.json_to_sheet(excelData);
|
|
355
|
+
XLSX.utils.book_append_sheet(workbook, sheet, '결과');
|
|
356
|
+
return Buffer.from(XLSX.write(workbook, { type: 'buffer', bookType: 'xlsx' }));
|
|
357
|
+
}
|
|
186
358
|
async issueSingleRow({ row, jobSno, managerSno, partnerSno, systemKey, longLivedToken, }) {
|
|
187
359
|
const { memberNo, amount, reason, expiredDt } = row;
|
|
188
360
|
const targetAmount = Number(amount);
|
|
361
|
+
const formattedExpiredDt = this.parseExcelDate(expiredDt);
|
|
189
362
|
if (!memberNo || isNaN(targetAmount) || targetAmount === 0 || !reason) {
|
|
190
363
|
throw new Error('필수 컬럼 누락 또는 금액 오류');
|
|
191
364
|
}
|
|
192
|
-
const member = await (0, gsUtil_1.shopByServerApi)('/profile', enum_1.HTTP_METHOD.GET, systemKey, longLivedToken, { memberNo
|
|
365
|
+
const member = await (0, gsUtil_1.shopByServerApi)('/profile', enum_1.HTTP_METHOD.GET, systemKey, longLivedToken, { memberNo });
|
|
193
366
|
if (!member)
|
|
194
367
|
throw new Error('존재하지 않는 회원');
|
|
195
368
|
const entityManager = await this.getEntityManager();
|
|
196
369
|
return await entityManager.transaction(async (manager) => {
|
|
197
|
-
var _a;
|
|
198
|
-
const [lastLedger] = await manager.query(`SELECT balanceAfter FROM gs_depositManager WHERE partnerSno = ? AND memberNo = ? ORDER BY sno DESC LIMIT 1 FOR UPDATE`, [partnerSno, memberNo]);
|
|
199
|
-
const prevBalance = Number((_a = lastLedger === null || lastLedger === void 0 ? void 0 : lastLedger.balanceAfter) !== null && _a !== void 0 ? _a : 0);
|
|
200
370
|
if (targetAmount > 0) {
|
|
201
|
-
|
|
202
|
-
jobSno,
|
|
371
|
+
return await this.processIssue(manager, {
|
|
203
372
|
partnerSno,
|
|
204
|
-
memberNo,
|
|
205
|
-
member
|
|
206
|
-
member
|
|
207
|
-
targetAmount,
|
|
373
|
+
memberNo: Number(memberNo),
|
|
374
|
+
memberId: member.memberId,
|
|
375
|
+
memberName: member.memberName,
|
|
376
|
+
amount: targetAmount,
|
|
208
377
|
reason,
|
|
209
|
-
expiredDt !== null && expiredDt !== void 0 ? expiredDt : null,
|
|
210
|
-
]);
|
|
211
|
-
await manager.query(`INSERT INTO gs_depositManager (partnerSno, memberNo, memberId, memberName, depositType, source, managerSno, refType, refSno, depositAmount, balanceAfter, reason)
|
|
212
|
-
VALUES (?, ?, ?, ?, 'ISSUE', 'ADMIN', ?, 'JOB_DETAIL', ?, ?, ?, ?)`, [
|
|
213
|
-
partnerSno,
|
|
214
|
-
memberNo,
|
|
215
|
-
member['memberId'],
|
|
216
|
-
member['memberName'],
|
|
217
378
|
managerSno,
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
reason,
|
|
222
|
-
]);
|
|
379
|
+
jobSno,
|
|
380
|
+
expiredDt: formattedExpiredDt ? formattedExpiredDt : null,
|
|
381
|
+
});
|
|
223
382
|
}
|
|
224
383
|
else {
|
|
225
|
-
|
|
226
|
-
if (prevBalance < deductAmount)
|
|
227
|
-
throw new Error(`잔액 부족 (가용: ${prevBalance})`);
|
|
228
|
-
const deductOrder = await manager.save(depositOrder_entity_1.DepositOrder, {
|
|
384
|
+
return await this.executeFifoDeduct(manager, {
|
|
229
385
|
partnerSno,
|
|
230
|
-
memberNo,
|
|
231
|
-
memberId: member
|
|
232
|
-
memberName: member
|
|
386
|
+
memberNo: Number(memberNo),
|
|
387
|
+
memberId: member.memberId,
|
|
388
|
+
memberName: member.memberName,
|
|
389
|
+
amount: Math.abs(targetAmount),
|
|
390
|
+
reason,
|
|
391
|
+
managerSno,
|
|
233
392
|
orderNo: `DEDUCT_EXCEL_${Date.now()}`,
|
|
234
|
-
usedAmount: deductAmount,
|
|
235
|
-
orderStatus: 'DONE',
|
|
236
393
|
});
|
|
237
|
-
const availableIssues = await manager.query(`SELECT jd.sno AS issueDetailSno, jd.depositAmount, jd.expiredDt, (jd.depositAmount - IFNULL(usedSub.netUsed, 0)) AS remainAmount
|
|
238
|
-
FROM gs_depositJobDetail jd
|
|
239
|
-
LEFT JOIN (SELECT issueDetailSno, SUM(usedDepositAmount - refundAmount) AS netUsed FROM gs_depositOrderDetail GROUP BY issueDetailSno) usedSub ON jd.sno = usedSub.issueDetailSno
|
|
240
|
-
WHERE jd.partnerSno = ? AND jd.memberNo = ? AND jd.expireFl = 'N' AND (jd.expiredDt IS NULL OR jd.expiredDt >= NOW())
|
|
241
|
-
HAVING remainAmount > 0 ORDER BY CASE WHEN jd.expiredDt IS NULL THEN 1 ELSE 0 END ASC, jd.expiredDt ASC, jd.sno ASC FOR UPDATE`, [partnerSno, memberNo]);
|
|
242
|
-
let remainToDeduct = deductAmount;
|
|
243
|
-
for (const issue of availableIssues) {
|
|
244
|
-
if (remainToDeduct <= 0)
|
|
245
|
-
break;
|
|
246
|
-
const take = Math.min(Number(issue.remainAmount), remainToDeduct);
|
|
247
|
-
await manager.save(depositOrderDetail_entity_1.DepositOrderDetail, {
|
|
248
|
-
orderSno: deductOrder.sno,
|
|
249
|
-
partnerSno,
|
|
250
|
-
memberNo,
|
|
251
|
-
orderProductOptionNo: 'ADMIN_DEDUCT',
|
|
252
|
-
mallProductNo: 'ADMIN_DEDUCT',
|
|
253
|
-
orderProductName: `관리자 차감: ${reason}`,
|
|
254
|
-
usedDepositAmount: take,
|
|
255
|
-
issueDetailSno: issue.issueDetailSno,
|
|
256
|
-
expireDt: issue.expiredDt,
|
|
257
|
-
refundYn: enum_1.YN.N,
|
|
258
|
-
});
|
|
259
|
-
remainToDeduct -= take;
|
|
260
|
-
}
|
|
261
|
-
await manager.query(`INSERT INTO gs_depositManager (partnerSno, memberNo, memberId, memberName, depositType, source, managerSno, refType, refSno, depositAmount, balanceAfter, reason)
|
|
262
|
-
VALUES (?, ?, ?, ?, 'CANCEL', 'ADMIN', ?, 'ORDER', ?, ?, ?, ?)`, [
|
|
263
|
-
partnerSno,
|
|
264
|
-
memberNo,
|
|
265
|
-
member['memberId'],
|
|
266
|
-
member['memberName'],
|
|
267
|
-
managerSno,
|
|
268
|
-
deductOrder.sno,
|
|
269
|
-
-deductAmount,
|
|
270
|
-
prevBalance - deductAmount,
|
|
271
|
-
reason,
|
|
272
|
-
]);
|
|
273
394
|
}
|
|
274
395
|
});
|
|
275
396
|
}
|
|
397
|
+
parseExcelDate(dateStr) {
|
|
398
|
+
if (!dateStr)
|
|
399
|
+
return null;
|
|
400
|
+
if (dateStr instanceof Date) {
|
|
401
|
+
dateStr.setHours(23, 59, 59, 0);
|
|
402
|
+
return dateStr;
|
|
403
|
+
}
|
|
404
|
+
if (typeof dateStr === 'number') {
|
|
405
|
+
const date = new Date((dateStr - 25569) * 86400 * 1000);
|
|
406
|
+
date.setHours(23, 59, 59, 0);
|
|
407
|
+
return isNaN(date.getTime()) ? null : date;
|
|
408
|
+
}
|
|
409
|
+
if (typeof dateStr === 'string') {
|
|
410
|
+
const normalized = dateStr.replace(/\./g, '-');
|
|
411
|
+
const date = new Date(normalized);
|
|
412
|
+
if (!isNaN(date.getTime())) {
|
|
413
|
+
date.setHours(23, 59, 59, 0);
|
|
414
|
+
return date;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
276
419
|
async getDepositManagerList(dto) {
|
|
277
420
|
const entityManager = await this.getEntityManager();
|
|
278
421
|
const qb = entityManager.createQueryBuilder(depositManager_entity_1.DepositManager, 'dm');
|
|
@@ -361,28 +504,30 @@ let DepositService = class DepositService extends default_service_1.DefaultServi
|
|
|
361
504
|
return detail;
|
|
362
505
|
}
|
|
363
506
|
async getOrderDetail(entityManager, sno, partnerSno) {
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
'
|
|
377
|
-
|
|
378
|
-
'
|
|
379
|
-
'
|
|
380
|
-
'
|
|
381
|
-
'
|
|
382
|
-
'od.
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
507
|
+
const managerEntry = await entityManager
|
|
508
|
+
.createQueryBuilder(depositManager_entity_1.DepositManager, 'dm')
|
|
509
|
+
.leftJoinAndSelect('gs_depositOrder', 'o', 'dm.refSno = o.sno AND dm.refType = "ORDER"')
|
|
510
|
+
.where('dm.sno = :sno AND dm.partnerSno = :partnerSno', {
|
|
511
|
+
sno,
|
|
512
|
+
partnerSno,
|
|
513
|
+
})
|
|
514
|
+
.getRawOne();
|
|
515
|
+
if (!managerEntry || !managerEntry.o_sno)
|
|
516
|
+
return null;
|
|
517
|
+
const usageDetails = await entityManager
|
|
518
|
+
.createQueryBuilder(depositOrderDetail_entity_1.DepositOrderDetail, 'od')
|
|
519
|
+
.leftJoin('gs_depositJobDetail', 'jd', 'od.issueDetailSno = jd.sno')
|
|
520
|
+
.select([
|
|
521
|
+
'jd.sno AS originSno',
|
|
522
|
+
'jd.regDt AS originRegDt',
|
|
523
|
+
'jd.reason AS originReason',
|
|
524
|
+
'jd.depositAmount AS originAmount',
|
|
525
|
+
'od.usedDepositAmount AS used',
|
|
526
|
+
'od.orderProductName AS pName',
|
|
527
|
+
])
|
|
528
|
+
.where('od.orderSno = :orderSno', { orderSno: managerEntry.o_sno })
|
|
529
|
+
.getRawMany();
|
|
530
|
+
return Object.assign(Object.assign({}, managerEntry), { usageDetails });
|
|
386
531
|
}
|
|
387
532
|
async createCouponManager(dto) {
|
|
388
533
|
if (dto.registerStartDt > dto.registerEndDt) {
|
|
@@ -419,7 +564,9 @@ let DepositService = class DepositService extends default_service_1.DefaultServi
|
|
|
419
564
|
async getCouponManagerList(dto) {
|
|
420
565
|
const entityManager = await this.getEntityManager();
|
|
421
566
|
const qb = entityManager.createQueryBuilder(depositCouponManager_entity_1.DepositCouponManager, 'dcm');
|
|
422
|
-
qb.andWhere('dcm.partnerSno = :partnerSno', {
|
|
567
|
+
qb.andWhere('dcm.partnerSno = :partnerSno', {
|
|
568
|
+
partnerSno: dto.partnerSno,
|
|
569
|
+
});
|
|
423
570
|
if (dto.title) {
|
|
424
571
|
qb.andWhere('dcm.title LIKE :title', {
|
|
425
572
|
title: `%${dto.title}%`,
|
|
@@ -447,14 +594,18 @@ let DepositService = class DepositService extends default_service_1.DefaultServi
|
|
|
447
594
|
async getCouponCodeList(dto) {
|
|
448
595
|
const entityManager = await this.getEntityManager();
|
|
449
596
|
const qb = entityManager.createQueryBuilder(depositCoupon_entity_1.DepositCoupon, 'dc');
|
|
450
|
-
qb.andWhere('dc.partnerSno = :partnerSno', {
|
|
597
|
+
qb.andWhere('dc.partnerSno = :partnerSno', {
|
|
598
|
+
partnerSno: dto.partnerSno,
|
|
599
|
+
});
|
|
451
600
|
if (dto.couponCode) {
|
|
452
601
|
qb.andWhere('dc.couponCode LIKE :couponCode', {
|
|
453
602
|
couponCode: `%${dto.couponCode}%`,
|
|
454
603
|
});
|
|
455
604
|
}
|
|
456
605
|
if (dto.policySno) {
|
|
457
|
-
qb.andWhere('dc.policySno = :policySno', {
|
|
606
|
+
qb.andWhere('dc.policySno = :policySno', {
|
|
607
|
+
policySno: dto.policySno,
|
|
608
|
+
});
|
|
458
609
|
}
|
|
459
610
|
qb.select(['dc.*']);
|
|
460
611
|
qb.orderBy('dc.sno', 'DESC');
|
|
@@ -480,7 +631,9 @@ let DepositService = class DepositService extends default_service_1.DefaultServi
|
|
|
480
631
|
.addSelect('SUM(od.usedDepositAmount)', 'usedAmount')
|
|
481
632
|
.from(depositOrderDetail_entity_1.DepositOrderDetail, 'od')
|
|
482
633
|
.groupBy('od.issueDetailSno'), 'od', 'jd.sno = od.issueDetailSno')
|
|
483
|
-
.where('jd.partnerSno = :partnerSno', {
|
|
634
|
+
.where('jd.partnerSno = :partnerSno', {
|
|
635
|
+
partnerSno: dto.partnerSno,
|
|
636
|
+
})
|
|
484
637
|
.andWhere('jd.expireFl = :expireFl', { expireFl: 'n' })
|
|
485
638
|
.andWhere('(jd.expiredDt IS NULL OR jd.expiredDt >= NOW())')
|
|
486
639
|
.groupBy('jd.memberNo')
|
|
@@ -491,7 +644,9 @@ let DepositService = class DepositService extends default_service_1.DefaultServi
|
|
|
491
644
|
const countQb = entityManager
|
|
492
645
|
.createQueryBuilder(depositJobDetail_entity_1.DepositJobDetail, 'jd')
|
|
493
646
|
.select('COUNT(DISTINCT jd.memberNo)', 'cnt')
|
|
494
|
-
.where('jd.partnerSno = :partnerSno', {
|
|
647
|
+
.where('jd.partnerSno = :partnerSno', {
|
|
648
|
+
partnerSno: dto.partnerSno,
|
|
649
|
+
})
|
|
495
650
|
.andWhere('jd.expireFl = :expireFl', { expireFl: 'n' })
|
|
496
651
|
.andWhere('(jd.expiredDt IS NULL OR jd.expiredDt >= NOW())');
|
|
497
652
|
const count = await countQb.getRawOne();
|
|
@@ -652,11 +807,17 @@ let DepositService = class DepositService extends default_service_1.DefaultServi
|
|
|
652
807
|
const entityManager = await this.getEntityManager();
|
|
653
808
|
const partner = await this.partnerService.findOne(dto.partnerSno);
|
|
654
809
|
if (!partner) {
|
|
655
|
-
return {
|
|
810
|
+
return {
|
|
811
|
+
rescode: '0002',
|
|
812
|
+
message: '유효하지 않은 파트너 정보입니다.',
|
|
813
|
+
};
|
|
656
814
|
}
|
|
657
815
|
const user = await (0, gsUtil_1.shopByServerApi)('/profile', enum_1.HTTP_METHOD.GET, partner.systemKey, partner.longLivedToken, { memberNo: Number(dto.memberMappingKey) });
|
|
658
816
|
if (!user) {
|
|
659
|
-
return {
|
|
817
|
+
return {
|
|
818
|
+
rescode: '0001',
|
|
819
|
+
message: '사용자 정보를 찾을 수 없습니다.',
|
|
820
|
+
};
|
|
660
821
|
}
|
|
661
822
|
const targetMemberNo = Number(user.memberNo);
|
|
662
823
|
const targetPartnerSno = partner.sno;
|
|
@@ -770,7 +931,8 @@ let DepositService = class DepositService extends default_service_1.DefaultServi
|
|
|
770
931
|
? remainToDeductMaster
|
|
771
932
|
: Math.round(depositOrder.usedAmount * ratio);
|
|
772
933
|
remainToDeductMaster -= amountToAllocate;
|
|
773
|
-
while (amountToAllocate > 0 &&
|
|
934
|
+
while (amountToAllocate > 0 &&
|
|
935
|
+
issueIndex < availableIssues.length) {
|
|
774
936
|
const currentIssue = availableIssues[issueIndex];
|
|
775
937
|
const canTake = Math.min(Number(currentIssue.remainAmount), amountToAllocate);
|
|
776
938
|
if (canTake > 0) {
|
|
@@ -854,8 +1016,10 @@ let DepositService = class DepositService extends default_service_1.DefaultServi
|
|
|
854
1016
|
});
|
|
855
1017
|
if (!usedDetails.length)
|
|
856
1018
|
continue;
|
|
857
|
-
const totalRemainQty = Number(usedDetails[0].orderCnt) -
|
|
858
|
-
|
|
1019
|
+
const totalRemainQty = Number(usedDetails[0].orderCnt) -
|
|
1020
|
+
Number(usedDetails[0].refundCnt);
|
|
1021
|
+
const totalRemainAmt = usedDetails.reduce((sum, d) => sum +
|
|
1022
|
+
(Number(d.usedDepositAmount) - Number(d.refundAmount)), 0);
|
|
859
1023
|
if (totalRemainAmt <= 0 || totalRemainQty <= 0)
|
|
860
1024
|
continue;
|
|
861
1025
|
const isFullCancel = Number(item.orderCnt) === Number(item.originalOrderCnt);
|
|
@@ -870,7 +1034,8 @@ let DepositService = class DepositService extends default_service_1.DefaultServi
|
|
|
870
1034
|
for (const detail of usedDetails) {
|
|
871
1035
|
if (remainRefundAmt <= 0)
|
|
872
1036
|
break;
|
|
873
|
-
const recordRemainAmt = Number(detail.usedDepositAmount) -
|
|
1037
|
+
const recordRemainAmt = Number(detail.usedDepositAmount) -
|
|
1038
|
+
Number(detail.refundAmount);
|
|
874
1039
|
if (recordRemainAmt <= 0)
|
|
875
1040
|
continue;
|
|
876
1041
|
const takeAmt = Math.min(recordRemainAmt, remainRefundAmt);
|
|
@@ -914,7 +1079,7 @@ let DepositService = class DepositService extends default_service_1.DefaultServi
|
|
|
914
1079
|
}
|
|
915
1080
|
};
|
|
916
1081
|
exports.DepositService = DepositService;
|
|
917
|
-
exports.DepositService = DepositService = __decorate([
|
|
1082
|
+
exports.DepositService = DepositService = DepositService_1 = __decorate([
|
|
918
1083
|
(0, common_1.Injectable)(),
|
|
919
1084
|
__metadata("design:paramtypes", [partner_service_1.PartnerService,
|
|
920
1085
|
core_1.ModuleRef])
|