polyv-live-cli
Version:
CLI tool for managing PolyV live streaming services.
375 lines • 17.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CouponHandler = void 0;
const base_handler_1 = require("./base.handler");
const sdk_1 = require("../sdk");
const errors_1 = require("../utils/errors");
const api_command_1 = require("../utils/api-command");
const COUPON_NAME_MAX_LENGTH = 50;
const BATCH_DELETE_MAX_IDS = 200;
const PAGE_SIZE_MAX = 1000;
class CouponHandler extends base_handler_1.BaseHandler {
constructor(authConfig, serviceConfig) {
super();
this.authConfig = authConfig;
this.serviceConfig = serviceConfig;
}
async addCoupon(options) {
return this.executeWithErrorHandling(async () => {
this.validateAddOptions(options);
const params = this.transformToAddParams(options);
const client = (0, sdk_1.createSdkClient)(this.authConfig, this.serviceConfig.baseUrl);
const couponId = await client.v4Platform.createCoupon(params);
this.displayAddResult(couponId, options.name, options.output);
}, 'coupon.add');
}
async listCoupons(options = {}) {
return this.executeWithErrorHandling(async () => {
this.validateListOptions(options);
const params = this.transformToListParams(options);
const client = (0, sdk_1.createSdkClient)(this.authConfig, this.serviceConfig.baseUrl);
const result = await client.v4Platform.searchCoupons(params);
this.displayListResult(result.contents, result.total, params.pageNumber ?? 1, params.pageSize ?? 10, options.output);
}, 'coupon.list');
}
async deleteCoupons(options) {
return this.executeWithErrorHandling(async () => {
this.validateDeleteOptions(options);
const client = (0, sdk_1.createSdkClient)(this.authConfig, this.serviceConfig.baseUrl);
await client.v4Platform.deleteCouponsBatch({ couponIds: options.couponIds });
this.displayDeleteResult(options.couponIds.length, options.output);
}, 'coupon.delete');
}
async getChannelCouponEnabled(options) {
return this.executeWithErrorHandling(async () => {
this.validateChannelId(options.channelId);
const client = (0, sdk_1.createSdkClient)(this.authConfig, this.serviceConfig.baseUrl);
const result = await client.v4Channel.getCouponEnabled({ channelId: options.channelId });
this.displayData(result, options.output || 'table');
}, 'coupon.channel.enabled');
}
async updateChannelCouponEnabled(options) {
return this.executeWithErrorHandling(async () => {
this.validateChannelId(options.channelId);
this.validateYn(options.enabled, 'enabled');
await (0, api_command_1.confirmWrite)(options.force, `Update channel coupon switch for channel ${options.channelId}?`);
const client = (0, sdk_1.createSdkClient)(this.authConfig, this.serviceConfig.baseUrl);
await client.v4Channel.updateCouponEnabled({
channelId: options.channelId,
enabled: options.enabled,
});
this.displayGenericWriteResult('Channel coupon switch updated successfully', {
channelId: options.channelId,
enabled: options.enabled,
}, options.output);
}, 'coupon.channel.update-enabled');
}
async listChannelCoupons(options) {
return this.executeWithErrorHandling(async () => {
this.validateChannelId(options.channelId);
this.validateChannelCouponListOptions(options);
const client = (0, sdk_1.createSdkClient)(this.authConfig, this.serviceConfig.baseUrl);
const result = await client.v4Channel.listChannelCoupons({
channelId: options.channelId,
pageNumber: options.page ?? 1,
pageSize: options.size ?? 10,
...(options.name && { name: options.name }),
});
this.displayData(result, options.output || 'table');
}, 'coupon.channel.list');
}
async addChannelCoupons(options) {
return this.executeWithErrorHandling(async () => {
this.validateChannelId(options.channelId);
this.validateChannelCouponIds(options.couponIds);
await (0, api_command_1.confirmWrite)(options.force, `Add ${options.couponIds.length} coupon(s) to channel ${options.channelId}?`);
const client = (0, sdk_1.createSdkClient)(this.authConfig, this.serviceConfig.baseUrl);
const result = await client.v4Channel.addChannelCoupon({
channelId: options.channelId,
couponIds: options.couponIds,
});
this.displayGenericWriteResult('Channel coupon(s) added successfully', {
channelId: options.channelId,
couponIds: options.couponIds,
result,
}, options.output);
}, 'coupon.channel.add');
}
async deleteChannelCoupons(options) {
return this.executeWithErrorHandling(async () => {
this.validateChannelId(options.channelId);
this.validateChannelCouponIds(options.couponIds);
await (0, api_command_1.confirmWrite)(options.force, `Delete ${options.couponIds.length} coupon(s) from channel ${options.channelId}?`);
const client = (0, sdk_1.createSdkClient)(this.authConfig, this.serviceConfig.baseUrl);
await client.v4Channel.deleteChannelCoupons({
channelId: options.channelId,
couponIds: options.couponIds,
});
this.displayGenericWriteResult('Channel coupon(s) deleted successfully', {
channelId: options.channelId,
couponIds: options.couponIds,
}, options.output);
}, 'coupon.channel.delete');
}
validateAddOptions(options) {
const errors = [];
if (!options.name || options.name.trim().length === 0) {
errors.push('name is required');
}
else if (options.name.length > COUPON_NAME_MAX_LENGTH) {
errors.push(`name must not exceed ${COUPON_NAME_MAX_LENGTH} characters`);
}
if (!options.type || !['MAX_OUT', 'DISCOUNT'].includes(options.type)) {
errors.push('type must be either MAX_OUT or DISCOUNT');
}
if (options.availableAmount === undefined || options.availableAmount < 0) {
errors.push('availableAmount must be >= 0');
}
if (!options.receiveStart || !options.receiveEnd) {
errors.push('receiveStart and receiveEnd are required');
}
else if (options.receiveStart >= options.receiveEnd) {
errors.push('receiveEnd must be greater than receiveStart');
}
if (!options.useTimeType || !['RANGE', 'DAY'].includes(options.useTimeType)) {
errors.push('useTimeType must be either RANGE or DAY');
}
if (options.useTimeType === 'RANGE') {
if (!options.useStart || !options.useEnd) {
errors.push('useStart and useEnd are required when useTimeType is RANGE');
}
else if (options.useStart >= options.useEnd) {
errors.push('useEnd must be greater than useStart');
}
}
if (options.useTimeType === 'DAY') {
if (options.dayOfUse === undefined || options.dayOfUse < 1) {
errors.push('dayOfUse is required and must be >= 1 when useTimeType is DAY');
}
}
if (!options.condition || !['UNCONDITIONAL', 'FULL_REDUCE'].includes(options.condition)) {
errors.push('condition must be either UNCONDITIONAL or FULL_REDUCE');
}
if (options.condition === 'UNCONDITIONAL') {
if (options.discount === undefined || options.discount <= 0) {
errors.push('discount is required and must be > 0 when condition is UNCONDITIONAL');
}
}
if (options.condition === 'FULL_REDUCE') {
if (options.full === undefined || options.full < 0) {
errors.push('full is required and must be >= 0 when condition is FULL_REDUCE');
}
if (options.reduce === undefined || options.reduce < 0) {
errors.push('reduce is required and must be >= 0 when condition is FULL_REDUCE');
}
}
if (options.limitPerPerson === undefined || options.limitPerPerson < -1) {
errors.push('limitPerPerson must be >= -1');
}
if (options.output !== undefined && !['table', 'json'].includes(options.output)) {
errors.push('output must be either "table" or "json"');
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`Coupon add options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
}
validateListOptions(options) {
const errors = [];
if (options.page !== undefined) {
if (typeof options.page !== 'number' || !Number.isInteger(options.page) || options.page < 1) {
errors.push('page must be a positive integer (minimum 1)');
}
}
if (options.size !== undefined) {
if (typeof options.size !== 'number' || !Number.isInteger(options.size) || options.size < 1 || options.size > PAGE_SIZE_MAX) {
errors.push(`size must be an integer between 1 and ${PAGE_SIZE_MAX}`);
}
}
if (options.status !== undefined && !['NOT_START', 'GOING', 'FINISHED', 'INVALID'].includes(options.status)) {
errors.push('status must be one of: NOT_START, GOING, FINISHED, INVALID');
}
if (options.output !== undefined && !['table', 'json'].includes(options.output)) {
errors.push('output must be either "table" or "json"');
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`Coupon list options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
}
validateDeleteOptions(options) {
const errors = [];
if (!options.couponIds || !Array.isArray(options.couponIds) || options.couponIds.length === 0) {
errors.push('couponIds is required and must not be empty');
}
else if (options.couponIds.length > BATCH_DELETE_MAX_IDS) {
errors.push(`couponIds must not exceed ${BATCH_DELETE_MAX_IDS} items`);
}
else {
const uniqueIds = new Set(options.couponIds);
if (uniqueIds.size !== options.couponIds.length) {
errors.push('couponIds contains duplicate values');
}
}
if (options.output !== undefined && !['table', 'json'].includes(options.output)) {
errors.push('output must be either "table" or "json"');
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`Coupon delete options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
}
validateChannelId(channelId) {
if (!channelId || channelId.trim() === '') {
throw new errors_1.PolyVValidationError('channelId is required', 'channelId', channelId, 'required');
}
}
validateYn(value, fieldName) {
if (value !== 'Y' && value !== 'N') {
throw new errors_1.PolyVValidationError(`${fieldName} must be Y or N`, fieldName, value, 'invalid_value');
}
}
validateChannelCouponListOptions(options) {
const errors = [];
if (options.page !== undefined && (!Number.isInteger(options.page) || options.page < 1)) {
errors.push('page must be a positive integer');
}
if (options.size !== undefined && (!Number.isInteger(options.size) || options.size < 1 || options.size > PAGE_SIZE_MAX)) {
errors.push(`size must be an integer between 1 and ${PAGE_SIZE_MAX}`);
}
if (options.output !== undefined && !['table', 'json'].includes(options.output)) {
errors.push('output must be either "table" or "json"');
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`Channel coupon list options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
}
validateChannelCouponIds(couponIds) {
if (!Array.isArray(couponIds) || couponIds.length === 0) {
throw new errors_1.PolyVValidationError('couponIds is required and must not be empty', 'couponIds', couponIds, 'required');
}
if (couponIds.length > 30) {
throw new errors_1.PolyVValidationError('couponIds must not exceed 30 items', 'couponIds', couponIds, 'max_items');
}
const uniqueIds = new Set(couponIds);
if (uniqueIds.size !== couponIds.length) {
throw new errors_1.PolyVValidationError('couponIds contains duplicate values', 'couponIds', couponIds, 'duplicate');
}
}
transformToAddParams(options) {
const rule = {
condition: options.condition,
limitPerPerson: options.limitPerPerson,
};
if (options.condition === 'UNCONDITIONAL') {
rule.unconditional = {
enable: true,
value: options.discount,
unit: options.type === 'DISCOUNT' ? 'DISCOUNT' : 'MONEY',
};
}
else if (options.condition === 'FULL_REDUCE') {
rule.fullReduce = {
enable: true,
full: options.full ?? 0,
reduce: options.reduce ?? 0,
unit: options.type === 'DISCOUNT' ? 'DISCOUNT' : 'MONEY',
};
}
const params = {
name: options.name,
type: options.type,
availableAmount: options.availableAmount,
receiveStartTime: options.receiveStart,
receiveEndTime: options.receiveEnd,
useTimeType: options.useTimeType,
rule,
};
if (options.useTimeType === 'RANGE') {
params.useStartTime = options.useStart;
params.useEndTime = options.useEnd;
}
else if (options.useTimeType === 'DAY') {
params.dayOfUse = options.dayOfUse;
}
return params;
}
transformToListParams(options) {
return {
pageNumber: options.page ?? 1,
pageSize: options.size ?? 10,
...(options.status && { status: options.status }),
};
}
displayAddResult(couponId, name, format = 'table') {
const data = {
couponId,
name,
created: new Date().toISOString(),
};
if (format === 'json') {
this.displayData(data, 'json');
}
else {
this.displaySuccess(`Coupon created successfully`, data, 'table');
}
}
displayListResult(coupons, total, page, size, format = 'table') {
if (coupons.length === 0) {
this.displayInfo('No coupons found');
return;
}
const fromItem = (page - 1) * size + 1;
const toItem = Math.min(fromItem + coupons.length - 1, fromItem + size - 1);
this.displayInfo(`Showing coupons ${fromItem}-${toItem} of ${total} (page ${page}, size ${size})`);
if (format === 'json') {
this.displayData(coupons, 'json');
}
else {
this.displayCouponsTable(coupons);
}
}
displayCouponsTable(coupons) {
const tableData = coupons.map((coupon) => ({
'Coupon ID': coupon.couponId,
'Name': coupon.name,
'Type': coupon.useTimeType === 'DAY' ? 'Days' : 'Range',
'Status': this.formatStatus(coupon.status),
'Available': coupon.availableAmount,
'Received': coupon.receivedAmount,
'Receive Period': `${this.formatDate(coupon.receiveStartTime)} - ${this.formatDate(coupon.receiveEndTime)}`,
}));
this.displayAsTable(tableData);
}
displayDeleteResult(count, format = 'table') {
const data = {
deleted: count,
timestamp: new Date().toISOString(),
};
if (format === 'json') {
this.displayData(data, 'json');
}
else {
this.displaySuccess(`Successfully deleted ${count} coupon(s)`, data, 'table');
}
}
displayGenericWriteResult(message, data, format = 'table') {
if (format === 'json') {
this.displayData({ success: true, data }, 'json');
}
else {
this.displaySuccess(message, data, 'table');
}
}
formatStatus(status) {
const statusMap = {
NOT_START: 'Not Started',
GOING: 'Active',
FINISHED: 'Finished',
INVALID: 'Invalid',
};
return statusMap[status] || status;
}
formatDate(timestamp) {
return new Date(timestamp).toLocaleDateString();
}
}
exports.CouponHandler = CouponHandler;
//# sourceMappingURL=coupon.handler.js.map