v1.6.8: remove offer exchange rate, add invoice item description, offer filters, table animations
- Remove exchange_rate and exchange_rate_date from quotations (schema, service, PDF, form) - Add item_description field to invoice_items (schema, migration, service, form, PDF) - Add offer status/customer/order filters with tab-based UI - Clean up offer statuses to active/ordered/invalidated - Allow invalidate action for non-ordered offers (not just expired) - Add fade animations on offers and invoices table data changes Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,7 @@ const ALLOWED_SORT_FIELDS = [
|
||||
|
||||
interface InvoiceItemInput {
|
||||
description?: string;
|
||||
item_description?: string;
|
||||
quantity?: number;
|
||||
unit?: string;
|
||||
unit_price?: number;
|
||||
@@ -374,6 +375,7 @@ export async function createInvoice(body: Record<string, any>) {
|
||||
data: (body.items as InvoiceItemInput[]).map((item, i) => ({
|
||||
invoice_id: invoice.id,
|
||||
description: item.description ?? null,
|
||||
item_description: item.item_description ?? null,
|
||||
quantity: item.quantity ?? 1,
|
||||
unit: item.unit ?? null,
|
||||
unit_price: item.unit_price ?? 0,
|
||||
@@ -471,6 +473,7 @@ export async function updateInvoice(id: number, body: Record<string, any>) {
|
||||
data: (body.items as InvoiceItemInput[]).map((item, i) => ({
|
||||
invoice_id: id,
|
||||
description: item.description ?? null,
|
||||
item_description: item.item_description ?? null,
|
||||
quantity: item.quantity ?? 1,
|
||||
unit: item.unit ?? null,
|
||||
unit_price: item.unit_price ?? 0,
|
||||
|
||||
@@ -44,6 +44,7 @@ interface ListOffersParams {
|
||||
search: string;
|
||||
status?: string;
|
||||
customer_id?: number;
|
||||
has_order?: string;
|
||||
}
|
||||
|
||||
function enrichQuotation(q: any) {
|
||||
@@ -72,13 +73,24 @@ function enrichQuotation(q: any) {
|
||||
}
|
||||
|
||||
export async function listOffers(params: ListOffersParams) {
|
||||
const { page, limit, skip, sort, order, search, status, customer_id } =
|
||||
params;
|
||||
const {
|
||||
page,
|
||||
limit,
|
||||
skip,
|
||||
sort,
|
||||
order,
|
||||
search,
|
||||
status,
|
||||
customer_id,
|
||||
has_order,
|
||||
} = params;
|
||||
const sortField = ALLOWED_SORT_FIELDS.includes(sort) ? sort : "id";
|
||||
|
||||
const where: Record<string, unknown> = {};
|
||||
if (status) where.status = status;
|
||||
if (customer_id) where.customer_id = customer_id;
|
||||
if (has_order === "yes") where.order_id = { not: null };
|
||||
if (has_order === "no") where.order_id = null;
|
||||
if (search) {
|
||||
where.OR = [
|
||||
{ quotation_number: { contains: search } },
|
||||
@@ -184,7 +196,6 @@ export async function createOffer(body: Record<string, any>) {
|
||||
language: body.language ? String(body.language) : "cs",
|
||||
vat_rate: body.vat_rate != null ? Number(body.vat_rate) : 21.0,
|
||||
apply_vat: body.apply_vat !== false,
|
||||
exchange_rate: body.exchange_rate ? Number(body.exchange_rate) : 1.0,
|
||||
status: body.status ? String(body.status) : "active",
|
||||
scope_title: body.scope_title ? String(body.scope_title) : null,
|
||||
scope_description: body.scope_description
|
||||
@@ -255,8 +266,6 @@ export async function updateOffer(id: number, body: Record<string, any>) {
|
||||
body.apply_vat === 1 ||
|
||||
body.apply_vat === "1"
|
||||
: undefined,
|
||||
exchange_rate:
|
||||
body.exchange_rate !== undefined ? Number(body.exchange_rate) : undefined,
|
||||
status: body.status !== undefined ? String(body.status) : undefined,
|
||||
project_code:
|
||||
body.project_code !== undefined
|
||||
@@ -354,7 +363,6 @@ export async function duplicateOffer(id: number) {
|
||||
language: original.language,
|
||||
vat_rate: original.vat_rate,
|
||||
apply_vat: original.apply_vat,
|
||||
exchange_rate: original.exchange_rate,
|
||||
status: "active",
|
||||
scope_title: original.scope_title,
|
||||
scope_description: original.scope_description,
|
||||
|
||||
@@ -206,7 +206,6 @@ export async function createOrderFromQuotation(
|
||||
language: quotation.language || "cs",
|
||||
vat_rate: quotation.vat_rate ?? 21.0,
|
||||
apply_vat: quotation.apply_vat ?? true,
|
||||
exchange_rate: quotation.exchange_rate ?? 1.0,
|
||||
scope_title: quotation.scope_title,
|
||||
scope_description: quotation.scope_description,
|
||||
attachment_data: attachmentBuffer
|
||||
|
||||
Reference in New Issue
Block a user