File size: 7,533 Bytes
0a5bd33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
import { NextRequest, NextResponse } from 'next/server';
import { getDb } from '@/lib/db';
import { OrderStatus, ProductType, QuoteOrder } from '@/types';

export async function GET(req: NextRequest) {
  try {
    const db = getDb();
    const { searchParams } = new URL(req.url);
    const status = searchParams.get('status');
    const search = searchParams.get('search');

    let query = 'SELECT * FROM quotes_orders WHERE 1=1';
    const params: unknown[] = [];

    if (status && status !== 'all') {
      query += ' AND status = ?';
      params.push(status);
    }

    if (search) {
      query += ' AND (code LIKE ? OR customer_name LIKE ? OR customer_phone LIKE ? OR job_name LIKE ?)';
      const term = `%${search}%`;
      params.push(term, term, term, term);
    }

    query += ' ORDER BY id DESC';

    const rows = db.prepare(query).all(...params) as Record<string, unknown>[];
    const orders: QuoteOrder[] = rows.map((r) => mapOrder(r));

    return NextResponse.json(orders);
  } catch (err: unknown) {
    return NextResponse.json({ error: (err as Error).message }, { status: 500 });
  }
}

export async function POST(req: NextRequest) {
  try {
    const body = await req.json();
    const db = getDb();

    // Sinh mã đơn hàng tự động: PC-YYYYMM-XXX
    const now = new Date();
    const yearMonth = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}`;
    const countRow = db.prepare('SELECT COUNT(*) as count FROM quotes_orders WHERE code LIKE ?').get(`PC-${yearMonth}-%`) as { count: number };
    const nextNum = String(countRow.count + 1).padStart(3, '0');
    const code = body.code || `PC-${yearMonth}-${nextNum}`;

    // Tự động thêm hoặc cập nhật khách hàng
    let customerId = body.customerId;
    if (!customerId && body.customerPhone) {
      const existingCust = db.prepare('SELECT id FROM customers WHERE phone = ?').get(body.customerPhone) as { id: number } | undefined;
      if (existingCust) {
        customerId = existingCust.id;
      } else if (body.customerName) {
        const custResult = db.prepare(`
          INSERT INTO customers (name, phone, email, company)
          VALUES (?, ?, ?, ?)
        `).run(body.customerName, body.customerPhone, body.customerEmail || '', body.customerCompany || '');
        customerId = Number(custResult.lastInsertRowid);
      }
    }

    const stmt = db.prepare(`
      INSERT INTO quotes_orders (
        code, customer_id, customer_name, customer_phone, customer_email, customer_company,
        job_name, product_type, print_tech, quantity, width_mm, height_mm, pages,
        paper_name, paper_gsm, parent_size, print_size, ups_per_sheet,
        total_print_sheets, total_parent_sheets, paper_cost, print_cost, finishing_cost,
        total_cost, profit_margin_percent, profit_amount, discount_amount,
        vat_percent, vat_amount, final_price, unit_price, status, notes, spec_json
      )
      VALUES (
        ?, ?, ?, ?, ?, ?,
        ?, ?, ?, ?, ?, ?, ?,
        ?, ?, ?, ?, ?,
        ?, ?, ?, ?, ?,
        ?, ?, ?, ?,
        ?, ?, ?, ?, ?, ?, ?
      )
    `);

    const result = stmt.run(
      code,
      customerId || null,
      body.customerName || 'Khách vãng lai',
      body.customerPhone || '',
      body.customerEmail || '',
      body.customerCompany || '',
      body.jobName || 'In ấn phẩm',
      body.productType || 'to_roi',
      body.printTech || 'offset',
      body.quantity,
      body.widthMm,
      body.heightMm,
      body.pages || 2,
      body.paperName,
      body.paperGsm,
      body.parentSize || '',
      body.printSize || '',
      body.upsPerSheet || 1,
      body.totalPrintSheets || 0,
      body.totalParentSheets || 0,
      body.paperCost || 0,
      body.printCost || 0,
      body.finishingCost || 0,
      body.totalCost || 0,
      body.profitMarginPercent || 25,
      body.profitAmount || 0,
      body.discountAmount || 0,
      body.vatPercent || 0,
      body.vatAmount || 0,
      body.finalPrice || 0,
      body.unitPrice || 0,
      body.status || 'quote',
      body.notes || '',
      body.specJson ? JSON.stringify(body.specJson) : null
    );

    return NextResponse.json({ success: true, id: Number(result.lastInsertRowid), code });
  } catch (err: unknown) {
    console.error('Order save error:', err);
    return NextResponse.json({ error: (err as Error).message }, { status: 500 });
  }
}

export async function PUT(req: NextRequest) {
  try {
    const body = await req.json();
    const db = getDb();

    if (body.action === 'status') {
      db.prepare(`
        UPDATE quotes_orders
        SET status = ?, updated_at = CURRENT_TIMESTAMP
        WHERE id = ?
      `).run(body.status, body.id);
    } else {
      db.prepare(`
        UPDATE quotes_orders
        SET customer_name = ?, customer_phone = ?, customer_email = ?, customer_company = ?,
            job_name = ?, status = ?, notes = ?, updated_at = CURRENT_TIMESTAMP
        WHERE id = ?
      `).run(
        body.customerName,
        body.customerPhone,
        body.customerEmail || '',
        body.customerCompany || '',
        body.jobName,
        body.status,
        body.notes || '',
        body.id
      );
    }

    return NextResponse.json({ success: true });
  } catch (err: unknown) {
    return NextResponse.json({ error: (err as Error).message }, { status: 500 });
  }
}

export async function DELETE(req: NextRequest) {
  try {
    const { searchParams } = new URL(req.url);
    const id = searchParams.get('id');
    if (!id) return NextResponse.json({ error: 'Thiếu ID đơn hàng' }, { status: 400 });

    const db = getDb();
    db.prepare('DELETE FROM quotes_orders WHERE id = ?').run(Number(id));
    return NextResponse.json({ success: true });
  } catch (err: unknown) {
    return NextResponse.json({ error: (err as Error).message }, { status: 500 });
  }
}

function mapOrder(r: Record<string, unknown>): QuoteOrder {
  return {
    id: r.id as number,
    code: r.code as string,
    customerId: r.customer_id as number | undefined,
    customerName: r.customer_name as string,
    customerPhone: r.customer_phone as string,
    customerEmail: (r.customer_email as string) || '',
    customerCompany: (r.customer_company as string) || '',
    jobName: r.job_name as string,
    productType: r.product_type as ProductType,
    printTech: r.print_tech as 'offset' | 'digital',
    quantity: r.quantity as number,
    widthMm: r.width_mm as number,
    heightMm: r.height_mm as number,
    pages: r.pages as number,
    paperName: r.paper_name as string,
    paperGsm: r.paper_gsm as number,
    parentSize: r.parent_size as string,
    printSize: r.print_size as string,
    upsPerSheet: r.ups_per_sheet as number,
    totalPrintSheets: r.total_print_sheets as number,
    totalParentSheets: r.total_parent_sheets as number,
    paperCost: r.paper_cost as number,
    printCost: r.print_cost as number,
    finishingCost: r.finishing_cost as number,
    totalCost: r.total_cost as number,
    profitMarginPercent: r.profit_margin_percent as number,
    profitAmount: r.profit_amount as number,
    discountAmount: r.discount_amount as number,
    vatPercent: r.vat_percent as number,
    vatAmount: r.vat_amount as number,
    finalPrice: r.final_price as number,
    unitPrice: r.unit_price as number,
    status: r.status as OrderStatus,
    notes: (r.notes as string) || '',
    specJson: (r.spec_json as string) || '',
    createdAt: r.created_at as string,
    updatedAt: r.updated_at as string,
  };
}