n8n-nodes-livo
Version:
n8n Livo App integration with triggers and actions for orders, products, customers, and repairs
314 lines (313 loc) • 16 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LivoRepairEvents = void 0;
const n8n_workflow_1 = require("n8n-workflow");
class LivoRepairEvents {
constructor() {
this.description = {
displayName: 'Livo Repair Events',
name: 'livoRepairEvents',
icon: 'file:repair.svg',
group: ['trigger'],
version: 1,
subtitle: '={{$parameter["eventType"]}}',
description: 'Lắng nghe các sự kiện dịch vụ sửa chữa từ ứng dụng Livo',
defaults: {
name: 'Livo Repair Events',
},
inputs: [],
outputs: ['main'],
webhooks: [
{
name: 'default',
httpMethod: 'POST',
responseMode: 'onReceived',
path: 'webhook',
},
],
properties: [
{
displayName: 'Event Type',
name: 'eventType',
type: 'options',
options: [
{
name: 'Lấy danh sách phiếu sửa chữa',
value: 'repair.list',
description: 'Trigger khi lấy danh sách phiếu sửa chữa',
},
{
name: 'Chi tiết phiếu sửa chữa',
value: 'repair.detail',
description: 'Trigger khi xem chi tiết phiếu sửa chữa',
},
{
name: 'Tạo phiếu sửa chữa',
value: 'repair.created',
description: 'Trigger khi tạo mới phiếu sửa chữa',
},
{
name: 'Cập nhật phiếu sửa chữa',
value: 'repair.updated',
description: 'Trigger khi cập nhật phiếu sửa chữa',
},
{
name: 'Thanh toán phiếu sửa chữa',
value: 'repair.paid',
description: 'Trigger khi thanh toán phiếu sửa chữa',
},
{
name: 'Xác nhận giao khách',
value: 'repair.customer_confirmed',
description: 'Trigger khi xác nhận giao khách thành công',
},
{
name: 'Hủy phiếu sửa chữa',
value: 'repair.cancelled',
description: 'Trigger khi hủy phiếu sửa chữa',
},
],
default: 'repair.created',
required: true,
},
{
displayName: 'Advanced Filters',
name: 'advancedFilters',
type: 'collection',
placeholder: 'Add Filter',
default: {},
options: [
{
displayName: 'Customer ID',
name: 'customerId',
type: 'string',
default: '',
description: 'Lọc theo mã khách hàng',
},
{
displayName: 'Device Type',
name: 'deviceType',
type: 'string',
default: '',
description: 'Lọc theo loại thiết bị',
},
{
displayName: 'Technician',
name: 'technician',
type: 'string',
default: '',
description: 'Lọc theo kỹ thuật viên',
},
{
displayName: 'Min Cost',
name: 'minCost',
type: 'number',
default: 0,
description: 'Chi phí sửa chữa tối thiểu',
},
{
displayName: 'Max Cost',
name: 'maxCost',
type: 'number',
default: 0,
description: 'Chi phí sửa chữa tối đa (0 = không giới hạn)',
},
{
displayName: 'Repair Status',
name: 'repairStatus',
type: 'string',
default: '',
description: 'Lọc theo trạng thái sửa chữa',
},
{
displayName: 'Priority',
name: 'priority',
type: 'options',
options: [
{ name: 'Low', value: 'low' },
{ name: 'Normal', value: 'normal' },
{ name: 'High', value: 'high' },
{ name: 'Urgent', value: 'urgent' },
],
default: '',
description: 'Lọc theo độ ưu tiên',
},
{
displayName: 'Assigned Staff',
name: 'assignedStaff',
type: 'string',
default: '',
description: 'Lọc theo nhân viên phụ trách',
},
{
displayName: 'Branch',
name: 'branch',
type: 'string',
default: '',
description: 'Lọc theo chi nhánh',
},
],
},
{
displayName: 'Authentication',
name: 'authentication',
type: 'collection',
placeholder: 'Add Authentication',
default: {},
options: [
{
displayName: 'Secret Token',
name: 'secretToken',
type: 'string',
typeOptions: {
password: true,
},
default: '',
description: 'Token bí mật để xác thực webhook',
},
{
displayName: 'Header Name',
name: 'headerName',
type: 'string',
default: 'X-Webhook-Secret',
description: 'Tên header chứa token xác thực',
},
],
},
],
};
}
async webhook() {
const bodyData = this.getBodyData();
const headers = this.getHeaderData();
const query = this.getQueryData();
const req = this.getRequestObject();
const expectedEventType = this.getNodeParameter('eventType');
const advancedFilters = this.getNodeParameter('advancedFilters', {});
const authentication = this.getNodeParameter('authentication', {});
if (authentication.secretToken) {
const headerName = authentication.headerName || 'X-Webhook-Secret';
const receivedToken = headers[headerName.toLowerCase()] || headers[headerName];
if (!receivedToken || receivedToken !== authentication.secretToken) {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Xác thực webhook thất bại: Token không hợp lệ');
}
}
if (!bodyData || typeof bodyData !== 'object') {
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Dữ liệu webhook không hợp lệ');
}
const eventData = bodyData;
const receivedEvent = eventData.event || headers['x-event-type'];
if (receivedEvent !== expectedEventType) {
return {
noWebhookResponse: true,
};
}
if (advancedFilters.customerId && eventData.customer_id !== advancedFilters.customerId) {
return { noWebhookResponse: true };
}
if (advancedFilters.deviceType && eventData.device_type !== advancedFilters.deviceType) {
return { noWebhookResponse: true };
}
if (advancedFilters.technician && eventData.technician !== advancedFilters.technician) {
return { noWebhookResponse: true };
}
if (advancedFilters.minCost && (eventData.repair_cost || 0) < advancedFilters.minCost) {
return { noWebhookResponse: true };
}
if (advancedFilters.maxCost && advancedFilters.maxCost > 0 &&
(eventData.repair_cost || 0) > advancedFilters.maxCost) {
return { noWebhookResponse: true };
}
if (advancedFilters.repairStatus && eventData.repair_status !== advancedFilters.repairStatus) {
return { noWebhookResponse: true };
}
if (advancedFilters.priority && eventData.priority !== advancedFilters.priority) {
return { noWebhookResponse: true };
}
if (advancedFilters.assignedStaff && eventData.assigned_staff !== advancedFilters.assignedStaff) {
return { noWebhookResponse: true };
}
if (advancedFilters.branch && eventData.branch !== advancedFilters.branch) {
return { noWebhookResponse: true };
}
const outputData = {
app_name: 'Livo',
event: receivedEvent,
event_time: new Date().toISOString(),
event_category: 'repair',
id: eventData.id || eventData.repair_id,
code: eventData.code || eventData.repair_code,
status: eventData.status || eventData.trang_thai,
created_date: eventData.created_date || eventData.ngay_tao,
updated_date: eventData.updated_date || eventData.ngay_cap_nhat,
assigned_staff: eventData.assigned_staff || eventData.nhan_vien_tiep_nhan,
branch: eventData.branch || eventData.chi_nhanh,
notes: eventData.notes || eventData.ghi_chu,
repair_id: eventData.repair_id || eventData.ma_phieu_sua,
repair_code: eventData.repair_code || eventData.ma_phieu,
ticket_number: eventData.ticket_number || eventData.so_phieu,
customer_id: eventData.customer_id || eventData.ma_khach_hang,
customer_name: eventData.customer_name || eventData.ten_khach_hang,
customer_phone: eventData.customer_phone || eventData.so_dien_thoai,
customer_email: eventData.customer_email || eventData.email,
customer_address: eventData.customer_address || eventData.dia_chi,
device_info: eventData.device_info || eventData.thong_tin_thiet_bi,
device_type: eventData.device_type || eventData.loai_thiet_bi,
device_brand: eventData.device_brand || eventData.hang_thiet_bi,
device_model: eventData.device_model || eventData.model_thiet_bi,
serial_number: eventData.serial_number || eventData.so_serial,
imei: eventData.imei || eventData.ma_imei,
device_condition: eventData.device_condition || eventData.tinh_trang_thiet_bi,
issue_description: eventData.issue_description || eventData.mo_ta_su_co,
issue_type: eventData.issue_type || eventData.loai_su_co,
symptoms: eventData.symptoms || eventData.trieu_chung,
error_codes: eventData.error_codes || eventData.ma_loi || [],
diagnosis: eventData.diagnosis || eventData.chan_doan,
repair_actions: eventData.repair_actions || eventData.hanh_dong_sua_chua,
replacement_parts: eventData.replacement_parts || eventData.linh_kien_thay_the || [],
technician: eventData.technician || eventData.ky_thuat_vien,
technical_notes: eventData.technical_notes || eventData.ghi_chu_ky_thuat,
repair_method: eventData.repair_method || eventData.phuong_phap_sua_chua,
estimated_time: eventData.estimated_time || eventData.thoi_gian_du_kien,
actual_time: eventData.actual_time || eventData.thoi_gian_thuc_te,
start_date: eventData.start_date || eventData.ngay_bat_dau,
completion_date: eventData.completion_date || eventData.ngay_hoan_thanh,
delivery_date: eventData.delivery_date || eventData.ngay_giao_khach,
pickup_date: eventData.pickup_date || eventData.ngay_nhan_may,
repair_cost: eventData.repair_cost || eventData.chi_phi_sua_chua,
parts_cost: eventData.parts_cost || eventData.tien_linh_kien,
labor_cost: eventData.labor_cost || eventData.tien_cong,
total_cost: eventData.total_cost || eventData.tong_chi_phi,
paid_amount: eventData.paid_amount || eventData.da_thanh_toan,
remaining_amount: eventData.remaining_amount || eventData.con_lai,
discount_amount: eventData.discount_amount || eventData.giam_gia,
repair_status: eventData.repair_status || eventData.trang_thai_sua_chua,
priority: eventData.priority || eventData.do_uu_tien,
warranty_status: eventData.warranty_status || eventData.tinh_trang_bao_hanh,
warranty_period: eventData.warranty_period || eventData.thoi_gian_bao_hanh,
is_under_warranty: eventData.is_under_warranty || eventData.trong_bao_hanh,
quality_check: eventData.quality_check || eventData.kiem_tra_chat_luong,
test_results: eventData.test_results || eventData.ket_qua_test || {},
customer_satisfaction: eventData.customer_satisfaction || eventData.muc_do_hai_long,
feedback: eventData.feedback || eventData.phan_hoi_khach_hang,
pickup_method: eventData.pickup_method || eventData.phuong_thuc_nhan_may,
delivery_method: eventData.delivery_method || eventData.phuong_thuc_giao_may,
pickup_address: eventData.pickup_address || eventData.dia_chi_nhan_may,
delivery_address: eventData.delivery_address || eventData.dia_chi_giao_may,
raw_data: eventData,
headers: headers,
query: query,
webhook_url: req.url,
};
return {
workflowData: [
[
{
json: outputData,
},
],
],
};
}
}
exports.LivoRepairEvents = LivoRepairEvents;