"feat: enhance invoice management with schema updates, seed data, and new APIs"
This commit is contained in:
187
03_source/cms_backend/prisma/seeds/_others.ts
Normal file
187
03_source/cms_backend/prisma/seeds/_others.ts
Normal file
@@ -0,0 +1,187 @@
|
||||
import { _mock } from './_mock';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export const _carouselsMembers = Array.from({ length: 6 }, (_, index) => ({
|
||||
id: _mock.id(index),
|
||||
name: _mock.fullName(index),
|
||||
role: _mock.role(index),
|
||||
avatarUrl: _mock.image.portrait(index),
|
||||
}));
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export const _faqs = Array.from({ length: 8 }, (_, index) => ({
|
||||
id: _mock.id(index),
|
||||
value: `panel${index + 1}`,
|
||||
heading: `Questions ${index + 1}`,
|
||||
detail: _mock.description(index),
|
||||
}));
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export const _addressBooks = Array.from({ length: 24 }, (_, index) => ({
|
||||
id: _mock.id(index),
|
||||
primary: index === 0,
|
||||
name: _mock.fullName(index),
|
||||
email: _mock.email(index + 1),
|
||||
fullAddress: _mock.fullAddress(index),
|
||||
phoneNumber: _mock.phoneNumber(index),
|
||||
company: _mock.companyNames(index + 1),
|
||||
addressType: index === 0 ? 'Home' : 'Office',
|
||||
}));
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export const _contacts = Array.from({ length: 20 }, (_, index) => {
|
||||
const status = (index % 2 && 'online') || (index % 3 && 'offline') || (index % 4 && 'always') || 'busy';
|
||||
|
||||
return {
|
||||
id: _mock.id(index),
|
||||
status,
|
||||
role: _mock.role(index),
|
||||
email: _mock.email(index),
|
||||
name: _mock.fullName(index),
|
||||
phoneNumber: _mock.phoneNumber(index),
|
||||
lastActivity: _mock.time(index),
|
||||
avatarUrl: _mock.image.avatar(index),
|
||||
address: _mock.fullAddress(index),
|
||||
};
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export const _notifications = Array.from({ length: 9 }, (_, index) => ({
|
||||
id: _mock.id(index),
|
||||
avatarUrl: [_mock.image.avatar(1), _mock.image.avatar(2), _mock.image.avatar(3), _mock.image.avatar(4), _mock.image.avatar(5), null, null, null, null, null][
|
||||
index
|
||||
],
|
||||
type: ['friend', 'project', 'file', 'tags', 'payment', 'order', 'delivery', 'chat', 'mail'][index],
|
||||
category: ['Communication', 'Project UI', 'File manager', 'File manager', 'File manager', 'Order', 'Order', 'Communication', 'Communication'][index],
|
||||
isUnRead: _mock.boolean(index),
|
||||
createdAt: _mock.time(index),
|
||||
title:
|
||||
(index === 0 && `<p><strong>Deja Brady</strong> sent you a friend request</p>`) ||
|
||||
(index === 1 && `<p><strong>Jayvon Hull</strong> mentioned you in <strong><a href='#'>Minimal UI</a></strong></p>`) ||
|
||||
(index === 2 && `<p><strong>Lainey Davidson</strong> added file to <strong><a href='#'>File manager</a></strong></p>`) ||
|
||||
(index === 3 && `<p><strong>Angelique Morse</strong> added new tags to <strong><a href='#'>File manager<a/></strong></p>`) ||
|
||||
(index === 4 && `<p><strong>Giana Brandt</strong> request a payment of <strong>$200</strong></p>`) ||
|
||||
(index === 5 && `<p>Your order is placed waiting for shipping</p>`) ||
|
||||
(index === 6 && `<p>Delivery processing your order is being shipped</p>`) ||
|
||||
(index === 7 && `<p>You have new message 5 unread messages</p>`) ||
|
||||
(index === 8 && `<p>You have new mail`) ||
|
||||
'',
|
||||
}));
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export const _mapContact = [
|
||||
{ latlng: [33, 65], address: _mock.fullAddress(1), phoneNumber: _mock.phoneNumber(1) },
|
||||
{ latlng: [-12.5, 18.5], address: _mock.fullAddress(2), phoneNumber: _mock.phoneNumber(2) },
|
||||
];
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export const _socials = [
|
||||
{
|
||||
value: 'facebook',
|
||||
label: 'Facebook',
|
||||
path: 'https://www.facebook.com/caitlyn.kerluke',
|
||||
},
|
||||
{
|
||||
value: 'instagram',
|
||||
label: 'Instagram',
|
||||
path: 'https://www.instagram.com/caitlyn.kerluke',
|
||||
},
|
||||
{
|
||||
value: 'linkedin',
|
||||
label: 'Linkedin',
|
||||
path: 'https://www.linkedin.com/caitlyn.kerluke',
|
||||
},
|
||||
{
|
||||
value: 'twitter',
|
||||
label: 'Twitter',
|
||||
path: 'https://www.twitter.com/caitlyn.kerluke',
|
||||
},
|
||||
];
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export const _pricingPlans = [
|
||||
{
|
||||
subscription: 'basic',
|
||||
price: 0,
|
||||
caption: 'Forever',
|
||||
lists: ['3 prototypes', '3 boards', 'Up to 5 team members'],
|
||||
labelAction: 'Current plan',
|
||||
},
|
||||
{
|
||||
subscription: 'starter',
|
||||
price: 4.99,
|
||||
caption: 'Saving $24 a year',
|
||||
lists: ['3 prototypes', '3 boards', 'Up to 5 team members', 'Advanced security', 'Issue escalation'],
|
||||
labelAction: 'Choose starter',
|
||||
},
|
||||
{
|
||||
subscription: 'premium',
|
||||
price: 9.99,
|
||||
caption: 'Saving $124 a year',
|
||||
lists: [
|
||||
'3 prototypes',
|
||||
'3 boards',
|
||||
'Up to 5 team members',
|
||||
'Advanced security',
|
||||
'Issue escalation',
|
||||
'Issue development license',
|
||||
'Permissions & workflows',
|
||||
],
|
||||
labelAction: 'Choose premium',
|
||||
},
|
||||
];
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export const _testimonials = [
|
||||
{
|
||||
name: _mock.fullName(1),
|
||||
postedDate: _mock.time(1),
|
||||
ratingNumber: _mock.number.rating(1),
|
||||
avatarUrl: _mock.image.avatar(1),
|
||||
content: `Excellent Work! Thanks a lot!`,
|
||||
},
|
||||
{
|
||||
name: _mock.fullName(2),
|
||||
postedDate: _mock.time(2),
|
||||
ratingNumber: _mock.number.rating(2),
|
||||
avatarUrl: _mock.image.avatar(2),
|
||||
content: `It's a very good dashboard and we are really liking the product . We've done some things, like migrate to TS and implementing a react useContext api, to fit our job methodology but the product is one of the best in terms of design and application architecture. The team did a really good job.`,
|
||||
},
|
||||
{
|
||||
name: _mock.fullName(3),
|
||||
postedDate: _mock.time(3),
|
||||
ratingNumber: _mock.number.rating(3),
|
||||
avatarUrl: _mock.image.avatar(3),
|
||||
content: `Customer support is realy fast and helpful the desgin of this theme is looks amazing also the code is very clean and readble realy good job !`,
|
||||
},
|
||||
{
|
||||
name: _mock.fullName(4),
|
||||
postedDate: _mock.time(4),
|
||||
ratingNumber: _mock.number.rating(4),
|
||||
avatarUrl: _mock.image.avatar(4),
|
||||
content: `Amazing, really good code quality and gives you a lot of examples for implementations.`,
|
||||
},
|
||||
{
|
||||
name: _mock.fullName(5),
|
||||
postedDate: _mock.time(5),
|
||||
ratingNumber: _mock.number.rating(5),
|
||||
avatarUrl: _mock.image.avatar(5),
|
||||
content: `Got a few questions after purchasing the product. The owner responded very fast and very helpfull. Overall the code is excellent and works very good. 5/5 stars!`,
|
||||
},
|
||||
{
|
||||
name: _mock.fullName(6),
|
||||
postedDate: _mock.time(6),
|
||||
ratingNumber: _mock.number.rating(6),
|
||||
avatarUrl: _mock.image.avatar(6),
|
||||
content: `CEO of Codealy.io here. We’ve built a developer assessment platform that makes sense - tasks are based on git repositories and run in virtual machines. We automate the pain points - storing candidates code, running it and sharing test results with the whole team, remotely. Bought this template as we need to provide an awesome dashboard for our early customers. I am super happy with purchase. The code is just as good as the design. Thanks!`,
|
||||
},
|
||||
];
|
76
03_source/cms_backend/prisma/seeds/invoiceItem.ts
Normal file
76
03_source/cms_backend/prisma/seeds/invoiceItem.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
import { _mock } from './_mock';
|
||||
import { _tags } from './assets';
|
||||
import { _addressBooks } from './_others';
|
||||
import { fSub, fAdd } from './utils/format-time';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export const INVOICE_SERVICE_OPTIONS = Array.from({ length: 8 }, (_, index) => ({
|
||||
id: _mock.id(index),
|
||||
name: _tags[index],
|
||||
price: _mock.number.price(index),
|
||||
}));
|
||||
|
||||
const ITEMS = Array.from({ length: 3 }, (__, index) => {
|
||||
const total = INVOICE_SERVICE_OPTIONS[index].price * _mock.number.nativeS(index);
|
||||
|
||||
return {
|
||||
id: _mock.id(index),
|
||||
total,
|
||||
title: _mock.productName(index),
|
||||
description: _mock.sentence(index),
|
||||
price: INVOICE_SERVICE_OPTIONS[index].price,
|
||||
service: INVOICE_SERVICE_OPTIONS[index].name,
|
||||
quantity: _mock.number.nativeS(index),
|
||||
};
|
||||
});
|
||||
|
||||
async function invoiceItem() {
|
||||
await prisma.orderItem.deleteMany({});
|
||||
|
||||
for (let index = 1; index < 3 + 1; index++) {
|
||||
const shipping = 10;
|
||||
const discount = 10;
|
||||
const taxes = 10;
|
||||
const items = (index % 2 && ITEMS.slice(0, 1)) || (index % 3 && ITEMS.slice(1, 3)) || ITEMS;
|
||||
const subtotal = items.reduce((accumulator, item) => accumulator + item.price * item.quantity, 0);
|
||||
const totalAmount = subtotal - shipping - discount + taxes;
|
||||
|
||||
const temp = await prisma.invoiceItem.upsert({
|
||||
where: { id: index.toString() },
|
||||
update: {},
|
||||
create: {
|
||||
id: index.toString(),
|
||||
taxes,
|
||||
status: (index % 2 && 'paid') || (index % 3 && 'pending') || (index % 4 && 'overdue') || 'draft',
|
||||
discount,
|
||||
shipping,
|
||||
subtotal: items.reduce((accumulator, item) => accumulator + item.price * item.quantity, 0),
|
||||
totalAmount,
|
||||
items,
|
||||
invoiceNumber: `INV-199${index}`,
|
||||
invoiceFrom: _addressBooks[index],
|
||||
invoiceTo: _addressBooks[index + 1],
|
||||
sent: _mock.number.nativeS(index),
|
||||
dueDate: new Date(fAdd({ days: index + 15, hours: index })),
|
||||
createdDate: new Date(fAdd({ days: index + 15, hours: index })),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
console.log('seed invoiceItem done');
|
||||
}
|
||||
|
||||
const invoiceItemSeed = invoiceItem()
|
||||
.then(async () => {
|
||||
await prisma.$disconnect();
|
||||
})
|
||||
.catch(async (e) => {
|
||||
console.error(e);
|
||||
await prisma.$disconnect();
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
export { invoiceItemSeed };
|
257
03_source/cms_backend/prisma/seeds/utils/format-time.ts
Normal file
257
03_source/cms_backend/prisma/seeds/utils/format-time.ts
Normal file
@@ -0,0 +1,257 @@
|
||||
import type { Dayjs, OpUnitType } from 'dayjs';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
import duration from 'dayjs/plugin/duration';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @Docs
|
||||
* https://day.js.org/docs/en/display/format
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default timezones
|
||||
* https://day.js.org/docs/en/timezone/set-default-timezone#docsNav
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* UTC
|
||||
* https://day.js.org/docs/en/plugin/utc
|
||||
* @install
|
||||
* import utc from 'dayjs/plugin/utc';
|
||||
* dayjs.extend(utc);
|
||||
* @usage
|
||||
* dayjs().utc().format()
|
||||
*
|
||||
*/
|
||||
|
||||
dayjs.extend(duration);
|
||||
dayjs.extend(relativeTime);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export type DatePickerFormat = Dayjs | Date | string | number | null | undefined;
|
||||
|
||||
export const formatPatterns = {
|
||||
dateTime: 'DD MMM YYYY h:mm a', // 17 Apr 2022 12:00 am
|
||||
date: 'DD MMM YYYY', // 17 Apr 2022
|
||||
time: 'h:mm a', // 12:00 am
|
||||
split: {
|
||||
dateTime: 'DD/MM/YYYY h:mm a', // 17/04/2022 12:00 am
|
||||
date: 'DD/MM/YYYY', // 17/04/2022
|
||||
},
|
||||
paramCase: {
|
||||
dateTime: 'DD-MM-YYYY h:mm a', // 17-04-2022 12:00 am
|
||||
date: 'DD-MM-YYYY', // 17-04-2022
|
||||
},
|
||||
};
|
||||
|
||||
const isValidDate = (date: DatePickerFormat) => date !== null && date !== undefined && dayjs(date).isValid();
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export function today(template?: string): string {
|
||||
return dayjs(new Date()).startOf('day').format(template);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @output 17 Apr 2022 12:00 am
|
||||
*/
|
||||
export function fDateTime(date: DatePickerFormat, template?: string): string {
|
||||
if (!isValidDate(date)) {
|
||||
return 'Invalid date';
|
||||
}
|
||||
|
||||
return dayjs(date).format(template ?? formatPatterns.dateTime);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @output 17 Apr 2022
|
||||
*/
|
||||
export function fDate(date: DatePickerFormat, template?: string): string {
|
||||
if (!isValidDate(date)) {
|
||||
return 'Invalid date';
|
||||
}
|
||||
|
||||
return dayjs(date).format(template ?? formatPatterns.date);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @output 12:00 am
|
||||
*/
|
||||
export function fTime(date: DatePickerFormat, template?: string): string {
|
||||
if (!isValidDate(date)) {
|
||||
return 'Invalid date';
|
||||
}
|
||||
|
||||
return dayjs(date).format(template ?? formatPatterns.time);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @output 1713250100
|
||||
*/
|
||||
export function fTimestamp(date: DatePickerFormat): number | 'Invalid date' {
|
||||
if (!isValidDate(date)) {
|
||||
return 'Invalid date';
|
||||
}
|
||||
|
||||
return dayjs(date).valueOf();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @output a few seconds, 2 years
|
||||
*/
|
||||
export function fToNow(date: DatePickerFormat): string {
|
||||
if (!isValidDate(date)) {
|
||||
return 'Invalid date';
|
||||
}
|
||||
|
||||
return dayjs(date).toNow(true);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @output boolean
|
||||
*/
|
||||
export function fIsBetween(inputDate: DatePickerFormat, startDate: DatePickerFormat, endDate: DatePickerFormat): boolean {
|
||||
if (!isValidDate(inputDate) || !isValidDate(startDate) || !isValidDate(endDate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const formattedInputDate = fTimestamp(inputDate);
|
||||
const formattedStartDate = fTimestamp(startDate);
|
||||
const formattedEndDate = fTimestamp(endDate);
|
||||
|
||||
if (formattedInputDate === 'Invalid date' || formattedStartDate === 'Invalid date' || formattedEndDate === 'Invalid date') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return formattedInputDate >= formattedStartDate && formattedInputDate <= formattedEndDate;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @output boolean
|
||||
*/
|
||||
export function fIsAfter(startDate: DatePickerFormat, endDate: DatePickerFormat): boolean {
|
||||
if (!isValidDate(startDate) || !isValidDate(endDate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return dayjs(startDate).isAfter(endDate);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @output boolean
|
||||
*/
|
||||
export function fIsSame(startDate: DatePickerFormat, endDate: DatePickerFormat, unitToCompare?: OpUnitType): boolean {
|
||||
if (!isValidDate(startDate) || !isValidDate(endDate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return dayjs(startDate).isSame(endDate, unitToCompare ?? 'year');
|
||||
}
|
||||
|
||||
/**
|
||||
* @output
|
||||
* Same day: 26 Apr 2024
|
||||
* Same month: 25 - 26 Apr 2024
|
||||
* Same month: 25 - 26 Apr 2024
|
||||
* Same year: 25 Apr - 26 May 2024
|
||||
*/
|
||||
export function fDateRangeShortLabel(startDate: DatePickerFormat, endDate: DatePickerFormat, initial?: boolean): string {
|
||||
if (!isValidDate(startDate) || !isValidDate(endDate) || fIsAfter(startDate, endDate)) {
|
||||
return 'Invalid date';
|
||||
}
|
||||
|
||||
let label = `${fDate(startDate)} - ${fDate(endDate)}`;
|
||||
|
||||
if (initial) {
|
||||
return label;
|
||||
}
|
||||
|
||||
const isSameYear = fIsSame(startDate, endDate, 'year');
|
||||
const isSameMonth = fIsSame(startDate, endDate, 'month');
|
||||
const isSameDay = fIsSame(startDate, endDate, 'day');
|
||||
|
||||
if (isSameYear && !isSameMonth) {
|
||||
label = `${fDate(startDate, 'DD MMM')} - ${fDate(endDate)}`;
|
||||
} else if (isSameYear && isSameMonth && !isSameDay) {
|
||||
label = `${fDate(startDate, 'DD')} - ${fDate(endDate)}`;
|
||||
} else if (isSameYear && isSameMonth && isSameDay) {
|
||||
label = `${fDate(endDate)}`;
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @output 2024-05-28T05:55:31+00:00
|
||||
*/
|
||||
export type DurationProps = {
|
||||
years?: number;
|
||||
months?: number;
|
||||
days?: number;
|
||||
hours?: number;
|
||||
minutes?: number;
|
||||
seconds?: number;
|
||||
milliseconds?: number;
|
||||
};
|
||||
|
||||
export function fAdd({ years = 0, months = 0, days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0 }: DurationProps) {
|
||||
const result = dayjs()
|
||||
.add(
|
||||
dayjs.duration({
|
||||
years,
|
||||
months,
|
||||
days,
|
||||
hours,
|
||||
minutes,
|
||||
seconds,
|
||||
milliseconds,
|
||||
})
|
||||
)
|
||||
.format();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @output 2024-05-28T05:55:31+00:00
|
||||
*/
|
||||
export function fSub({ years = 0, months = 0, days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0 }: DurationProps) {
|
||||
const result = dayjs()
|
||||
.subtract(
|
||||
dayjs.duration({
|
||||
years,
|
||||
months,
|
||||
days,
|
||||
hours,
|
||||
minutes,
|
||||
seconds,
|
||||
milliseconds,
|
||||
})
|
||||
)
|
||||
.format();
|
||||
|
||||
return result;
|
||||
}
|
Reference in New Issue
Block a user