'use strict'; const test = require('node:test'); const assert = require('node:assert/strict'); const { listPresaleTasks, _test: { getActionType, normalizeInput, normalizeRunDate }, } = require('../src/services/presaleTaskService'); test('presale task input requires a DingTalk user and validates run date', () => { assert.throws(() => normalizeInput({}), /dingtalkUserId|dingtalkUserName/); assert.throws(() => normalizeRunDate('2026-02-30'), /有效日期/); assert.equal(normalizeRunDate('2026-07-29'), '2026-07-29'); }); test('presale action type distinguishes create, extend, cancel and no action', () => { assert.equal(getActionType({ notice_remark: '新增预售' }), 'CREATE_PRESALE'); assert.equal(getActionType({ notice_remark: '延长预售' }), 'EXTEND_PRESALE'); assert.equal(getActionType({ presale_policy: '取消预售' }), 'CANCEL_PRESALE'); assert.equal(getActionType({ notice_remark: '2026-07-23 已通知' }), 'NO_ACTION'); }); test('presale task query returns the standard paged external API payload', async () => { const calls = []; const query = async (sql, params) => { calls.push({ sql, params }); if (sql.includes('MAX(run_date)')) return [{ run_date: '2026-07-29' }]; if (sql.includes('COUNT(*) AS total_rows')) { return [{ total_rows: 16, product_count: 9, actionable_rows: 8, create_presale_rows: 1, extend_presale_rows: 5, cancel_presale_rows: 2, no_action_rows: 8, }]; } return [{ run_date: '2026-07-29', notice_time: '2026-07-29 11:08:52', notice_remark: '延长预售', ider: '香茗', ider_userid: 'ding-user-id', shopname: '拼多多-亿家木家具旗舰店', shop_i_id: '972878614785', shop_sku_id: '1926066156590', sku_id: 'SZ015911N851V01', presale_policy: '预售', presale_deadline: '2026-08-01 00:00:00', }]; }; const result = await listPresaleTasks( { dingtalkUserName: '香茗', pageSize: 20 }, { query } ); assert.equal(result.runDate, '2026-07-29'); assert.deepEqual(result.recipient, { dingtalkUserId: 'ding-user-id', dingtalkUserName: '香茗', }); assert.equal(result.summary.totalRows, 16); assert.equal(result.summary.actionableRows, 8); assert.equal(result.pagination.totalPages, 1); assert.equal(result.items[0].actionType, 'EXTEND_PRESALE'); assert.equal(result.items[0].requiresAction, true); assert.equal(calls.length, 3); assert.equal(calls[0].params.dingtalkUserName, '香茗'); assert.equal(calls[2].params.pageSize, 20); }); test('actionableOnly is applied to both summary and item queries', async () => { const calls = []; const query = async (sql) => { calls.push(sql); if (sql.includes('COUNT(*) AS total_rows')) return [{ total_rows: 0 }]; return []; }; await listPresaleTasks( { dingtalkUserId: 'ding-user-id', runDate: '2026-07-29', actionableOnly: true }, { query } ); assert.equal(calls.length, 2); assert.ok(calls.every((sql) => sql.includes('notice_remark IN'))); });