import InvoiceIcon from '../../components/Icons/InvoiceIcon' import InfoCircleIcon from '../../components/Icons/InfoCircleIcon' import CheckIcon from '../../components/Icons/CheckIcon' import EditIcon from '../../components/Icons/EditIcon' import XMarkIcon from '../../components/Icons/XMarkIcon' import BinIcon from '../../components/Icons/BinIcon' import PlusIcon from '../../components/Icons/PlusIcon' export const Invoice = { name: 'invoice', label: 'Invoice', prefix: 'INV', icon: InvoiceIcon, actions: [ { name: 'info', label: 'Info', default: true, row: true, icon: InfoCircleIcon, url: (_id) => `/dashboard/finance/invoices/info?invoiceId=${_id}` }, { name: 'edit', label: 'Edit', type: 'button', icon: EditIcon, url: (_id) => `/dashboard/finance/invoices/info?invoiceId=${_id}&action=edit`, visible: (objectData) => { return !(objectData?._isEditing && objectData?._isEditing == true) }, disabled: (objectData) => { return objectData?.state?.type != 'draft' } }, { name: 'cancelEdit', label: 'Cancel Edit', type: 'button', icon: XMarkIcon, url: (_id) => `/dashboard/finance/invoices/info?invoiceId=${_id}&action=cancelEdit`, visible: (objectData) => { return objectData?._isEditing && objectData?._isEditing == true } }, { name: 'finishEdit', label: 'Finish Edit', type: 'button', icon: CheckIcon, url: (_id) => `/dashboard/finance/invoices/info?invoiceId=${_id}&action=finishEdit`, visible: (objectData) => { return objectData?._isEditing && objectData?._isEditing == true } }, { name: 'delete', label: 'Delete', type: 'button', icon: BinIcon, danger: true, url: (_id) => `/dashboard/finance/invoices/info?invoiceId=${_id}&action=delete`, visible: (objectData) => { return !(objectData?._isEditing && objectData?._isEditing == true) }, disabled: (objectData) => { return objectData?.state?.type != 'draft' } }, { type: 'divider' }, { name: 'newPayment', label: 'New Payment', type: 'button', icon: PlusIcon, url: (_id) => `/dashboard/finance/invoices/info?invoiceId=${_id}&action=newPayment`, disabled: (objectData) => { const allowedStates = ['acknowledged', 'partiallyPaid', 'overdue'] return !allowedStates.includes(objectData?.state?.type) } }, { type: 'divider' }, { name: 'post', label: 'Post', type: 'button', icon: CheckIcon, url: (_id) => `/dashboard/finance/invoices/info?invoiceId=${_id}&action=post`, visible: (objectData) => { return objectData?.state?.type == 'draft' } }, { name: 'acknowledge', label: 'Acknowledge', type: 'button', icon: CheckIcon, url: (_id) => `/dashboard/finance/invoices/info?invoiceId=${_id}&action=acknowledge`, visible: (objectData) => { return objectData?.state?.type == 'sent' } }, { name: 'cancel', label: 'Cancel', type: 'button', icon: XMarkIcon, danger: true, url: (_id) => `/dashboard/finance/invoices/info?invoiceId=${_id}&action=cancel`, disabled: (objectData) => { const allowedStates = [ 'acknowledged', 'partiallyPaid', 'overdue', 'sent' ] return !allowedStates.includes(objectData?.state?.type) }, visible: (objectData) => { return objectData?.state?.type != 'draft' } } ], group: ['orderType'], filters: ['to', 'from', 'orderType'], sorters: ['createdAt', 'state', 'updatedAt', 'invoiceDate', 'dueDate'], columns: [ '_reference', 'state', 'orderType', 'to', 'from', 'invoiceDate', 'dueDate', 'totalAmount', 'totalAmountWithTax', 'totalTaxAmount', 'shippingAmount', 'shippingAmountWithTax', 'grandTotalAmount', 'createdAt', 'updatedAt' ], properties: [ { name: '_id', label: 'ID', type: 'id', columnFixed: 'left', objectType: 'invoice', columnWidth: 140, showCopy: true }, { name: 'createdAt', label: 'Created At', type: 'dateTime', readOnly: true, columnWidth: 175 }, { name: '_reference', label: 'Reference', type: 'reference', columnFixed: 'left', required: true, objectType: 'invoice', showCopy: true, readOnly: true, columnWidth: 180 }, { name: 'updatedAt', label: 'Updated At', type: 'dateTime', readOnly: true, columnWidth: 175 }, { name: 'state', label: 'State', type: 'state', readOnly: true, columnWidth: 250 }, { name: 'issuedAt', label: 'Issued At', type: 'dateTime', readOnly: false, required: true, columnWidth: 175 }, { name: 'orderType', label: 'Order Type', type: 'objectType', masterFilter: ['purchaseOrder', 'salesOrder'], required: true, columnWidth: 150 }, { name: 'dueAt', label: 'Due At', type: 'dateTime', required: true, columnWidth: 175 }, { name: 'order', label: 'Order', type: 'object', objectType: (objectData) => { return objectData?.orderType }, required: true, showHyperlink: true, columnWidth: 200 }, { name: 'postedAt', label: 'Posted At', type: 'dateTime', readOnly: true, columnWidth: 175 }, { name: 'fromType', label: 'From Type', type: 'objectType', value: (objectData) => { return objectData?.orderType == 'purchaseOrder' ? 'vendor' : objectData?.fromType }, masterFilter: ['client', 'vendor'], readOnly: (objectData) => { return objectData?.orderType == 'purchaseOrder' ? true : false }, columnWidth: 150, required: true }, { name: 'acknowledgedAt', label: 'Acknowledged At', type: 'dateTime', readOnly: true, columnWidth: 175 }, { name: 'from', label: 'From', required: true, type: 'object', objectType: (objectData) => { return objectData?.fromType }, showHyperlink: true, readOnly: (objectData) => { return objectData?.orderType == 'purchaseOrder' ? true : false }, columnWidth: 200, value: (objectData) => { if (objectData?.orderType == 'purchaseOrder') { return objectData?.order?.vendor } else { return objectData?.from } } }, { name: 'cancelledAt', label: 'Cancelled At', type: 'dateTime', readOnly: true, columnWidth: 175 }, { name: 'toType', label: 'To Type', type: 'objectType', masterFilter: ['vendor', 'client'], value: (objectData) => { return objectData?.orderType == 'salesOrder' ? 'client' : objectData?.toType }, readOnly: (objectData) => { return objectData?.orderType == 'salesOrder' ? true : false }, columnWidth: 150, required: true }, { name: 'to', label: 'To', required: true, type: 'object', objectType: (objectData) => { return objectData?.toType }, showHyperlink: true, readOnly: (objectData) => { return objectData?.orderType == 'salesOrder' ? true : false }, columnWidth: 200, value: (objectData) => { if (objectData?.orderType == 'salesOrder') { return objectData?.order?.client } else { return objectData?.to } } }, { name: 'totalTaxAmount', label: 'Total Tax Amount', type: 'number', prefix: '£', roundNumber: 2, readOnly: true, columnWidth: 175 }, { name: 'paidAt', label: 'Paid At', type: 'dateTime', readOnly: true, columnWidth: 175 }, { name: 'totalAmountWithTax', label: 'Total Amount w/ Tax', type: 'number', prefix: '£', readOnly: true, columnWidth: 175, roundNumber: 2 }, { name: 'shippingAmount', label: 'Shipping Amount', type: 'number', prefix: '£', roundNumber: 2, readOnly: true, columnWidth: 150 }, { name: 'shippingAmountWithTax', label: 'Shipping Amount w/ Tax', type: 'number', prefix: '£', readOnly: true, roundNumber: 2, columnWidth: 200 }, { name: 'totalAmount', label: 'Total Amount', type: 'number', prefix: '£', roundNumber: 2, readOnly: true, columnWidth: 150 }, { name: 'grandTotalAmount', label: 'Grand Total Amount', type: 'number', prefix: '£', roundNumber: 2, columnWidth: 175, readOnly: true }, { name: 'invoiceOrderItems', label: 'Invoice Order Items', type: 'objectChildren', objectType: 'orderItem', properties: [ { name: 'orderItem', label: 'Order Item', type: 'object', objectType: 'orderItem', required: true, columnWidth: 300, showHyperlink: true }, { name: 'invoiceQuantity', label: 'Quantity', type: 'number', required: true, columnWidth: 175 }, { name: 'invoiceAmount', label: 'Invoice Amount', type: 'number', prefix: '£', roundNumber: 2, required: true, columnWidth: 150 }, { name: 'taxRate', label: 'Tax Rate', type: 'object', objectType: 'taxRate', required: false, showHyperlink: true, columnWidth: 200 }, { name: 'invoiceAmountWithTax', label: 'Invoice Amount w/ Tax', type: 'number', prefix: '£', roundNumber: 2, required: true, readOnly: true, columnWidth: 200, value: (objectData) => { const invoiceAmount = objectData?.invoiceAmount || 0 if (!invoiceAmount) return 0 if (objectData?.taxRate?.rateType == 'percentage') { return ( (invoiceAmount * (1 + objectData?.taxRate?.rate / 100)).toFixed( 2 ) || 0 ) } else if (objectData?.taxRate?.rateType == 'amount') { return (invoiceAmount + objectData?.taxRate?.rate).toFixed(2) || 0 } return invoiceAmount } } ], rollups: [ { name: 'totalQuantity', label: 'Total Quantity', type: 'number', property: 'invoiceQuantity', value: (objectData) => { return objectData?.invoiceOrderItems?.reduce( (acc, item) => acc + (item.invoiceQuantity || 0), 0 ) } }, { name: 'totalAmount', label: 'Total Amount', type: 'number', property: 'invoiceAmount', prefix: '£', fixedNumber: 2, value: (objectData) => { return objectData?.invoiceOrderItems ?.reduce( (acc, item) => acc + (Number.parseFloat(item.invoiceAmount) || 0), 0 ) .toFixed(2) } }, { name: 'totalAmountWithTax', label: 'Total Amount w/ Tax', type: 'number', property: 'invoiceAmountWithTax', prefix: '£', fixedNumber: 2, value: (objectData) => { return objectData?.invoiceOrderItems ?.reduce( (acc, item) => acc + (Number.parseFloat(item.invoiceAmountWithTax) || 0), 0 ) .toFixed(2) } } ] }, { name: 'invoiceShipments', label: 'Invoice Shipments', type: 'objectChildren', objectType: 'shipment', properties: [ { name: 'shipment', label: 'Shipment', type: 'object', objectType: 'shipment', required: true, columnWidth: 300, showHyperlink: true }, { name: 'invoiceAmount', label: 'Invoice Amount', type: 'number', prefix: '£', roundNumber: 2, columnWidth: 175, required: true }, { name: 'taxRate', label: 'Tax Rate', type: 'object', objectType: 'taxRate', required: false, showHyperlink: true, columnWidth: 200 }, { name: 'invoiceAmountWithTax', label: 'Invoice Amount w/ Tax', type: 'number', prefix: '£', roundNumber: 2, required: true, readOnly: true, columnWidth: 200, value: (objectData) => { const invoiceAmount = objectData?.invoiceAmount || 0 if (!invoiceAmount) return 0 if (objectData?.taxRate?.rateType == 'percentage') { return ( (invoiceAmount * (1 + objectData?.taxRate?.rate / 100)).toFixed( 2 ) || 0 ) } else if (objectData?.taxRate?.rateType == 'amount') { return (invoiceAmount + objectData?.taxRate?.rate).toFixed(2) || 0 } return invoiceAmount } } ], rollups: [ { name: 'totalAmount', label: 'Total Amount', type: 'number', property: 'invoiceAmount', prefix: '£', roundNumber: 2, value: (objectData) => { return objectData?.invoiceShipments ?.reduce( (acc, shipment) => acc + (shipment.invoiceAmount || 0), 0 ) .toFixed(2) } }, { name: 'totalAmountWithTax', label: 'Total Amount w/ Tax', type: 'number', property: 'invoiceAmountWithTax', prefix: '£', roundNumber: 2, value: (objectData) => { return objectData?.invoiceShipments ?.reduce( (acc, shipment) => acc + (Number.parseFloat(shipment.invoiceAmountWithTax) || 0), 0 ) .toFixed(2) } } ] } ], stats: [ { name: 'draft.draftCount.count', label: 'Draft', type: 'number', color: 'default' }, { name: 'draft.draftGrandTotalAmount.sum', label: 'Draft Grand Total Amount', type: 'number', prefix: '£', roundNumber: 2, color: 'default' }, { name: 'sent.sentCount.count', label: 'Sent', type: 'number', color: 'cyan' }, { name: 'acknowledged.acknowledgedCount.count', label: 'Acknowledged', type: 'number', color: 'purple' }, { name: 'due.dueCount.count', label: 'Due', type: 'number', color: 'warning', sum: [ 'sent.sentCount.count', 'partiallyPaid.partiallyPaidCount.count', 'overdue.overdueCount.count', 'acknowledged.acknowledgedCount.count' ] }, { name: 'due.dueGrandTotalAmount.sum', label: 'Due Grand Total Amount', type: 'number', prefix: '£', roundNumber: 2, color: 'warning', sum: [ 'sent.sentGrandTotalAmount.sum', 'partiallyPaid.partiallyPaidGrandTotalAmount.sum', 'overdue.overdueGrandTotalAmount.sum', 'acknowledged.acknowledgedGrandTotalAmount.sum' ] }, { name: 'partiallyPaid.partiallyPaidCount.count', label: 'Partially Paid', type: 'number', color: 'processing' }, { name: 'overdue.overdueCount.count', label: 'Overdue', type: 'number', color: 'error' }, { name: 'overdue.overdueGrandTotalAmount.sum', label: 'Overdue Grand Total Amount', type: 'number', prefix: '£', roundNumber: 2, color: 'error' } ] }