mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 06:40:31 +00:00
Merge pull request #882 from bigcapitalhq/bugs-bashing2
Bug fixes, refactoring, and improvements
This commit is contained in:
@@ -1,4 +1,27 @@
|
|||||||
// import { getTransactionsLockingSettingsSchema } from '@/api/controllers/TransactionsLocking/utils';
|
import { chain, mapKeys } from 'lodash';
|
||||||
|
|
||||||
|
const getTransactionsLockingSettingsSchema = (modules: string[]) => {
|
||||||
|
const moduleSchema = {
|
||||||
|
active: { type: 'boolean' },
|
||||||
|
lock_to_date: { type: 'date' },
|
||||||
|
unlock_from_date: { type: 'date' },
|
||||||
|
unlock_to_date: { type: 'date' },
|
||||||
|
lock_reason: { type: 'string' },
|
||||||
|
unlock_reason: { type: 'string' },
|
||||||
|
};
|
||||||
|
return chain(modules)
|
||||||
|
.map((module: string) => {
|
||||||
|
return mapKeys(moduleSchema, (value, key: string) => `${module}.${key}`);
|
||||||
|
})
|
||||||
|
.flattenDeep()
|
||||||
|
.reduce((result, value) => {
|
||||||
|
return {
|
||||||
|
...result,
|
||||||
|
...value,
|
||||||
|
};
|
||||||
|
}, {})
|
||||||
|
.value();
|
||||||
|
};
|
||||||
|
|
||||||
export const SettingsOptions = {
|
export const SettingsOptions = {
|
||||||
organization: {
|
organization: {
|
||||||
@@ -223,12 +246,12 @@ export const SettingsOptions = {
|
|||||||
'locking-type': {
|
'locking-type': {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
},
|
},
|
||||||
// ...getTransactionsLockingSettingsSchema([
|
...getTransactionsLockingSettingsSchema([
|
||||||
// 'all',
|
'all',
|
||||||
// 'sales',
|
'sales',
|
||||||
// 'purchases',
|
'purchases',
|
||||||
// 'financial',
|
'financial',
|
||||||
// ]),
|
]),
|
||||||
},
|
},
|
||||||
features: {
|
features: {
|
||||||
'multi-warehouses': {
|
'multi-warehouses': {
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { ChromiumlyTenancy } from '../ChromiumlyTenancy/ChromiumlyTenancy.service';
|
import { ChromiumlyTenancy } from '../ChromiumlyTenancy/ChromiumlyTenancy.service';
|
||||||
import { TemplateInjectable } from '../TemplateInjectable/TemplateInjectable.service';
|
import { renderExportResourceTableTemplateHtml } from '@bigcapital/pdf-templates';
|
||||||
import { mapPdfRows } from './utils';
|
import { mapPdfRows } from './utils';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ExportPdf {
|
export class ExportPdf {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly templateInjectable: TemplateInjectable,
|
|
||||||
private readonly chromiumlyTenancy: ChromiumlyTenancy,
|
private readonly chromiumlyTenancy: ChromiumlyTenancy,
|
||||||
) {}
|
) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the pdf table sheet for the given data and columns.
|
* Generates the pdf table sheet for the given data and columns.
|
||||||
@@ -19,21 +18,18 @@ export class ExportPdf {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public async pdf(
|
public async pdf(
|
||||||
columns: { accessor: string },
|
columns: { accessor: string; name?: string; style?: string; group?: string }[],
|
||||||
data: Record<string, any>,
|
data: Record<string, any>,
|
||||||
sheetTitle: string = '',
|
sheetTitle: string = '',
|
||||||
sheetDescription: string = ''
|
sheetDescription: string = ''
|
||||||
) {
|
) {
|
||||||
const rows = mapPdfRows(columns, data);
|
const rows = mapPdfRows(columns, data);
|
||||||
|
|
||||||
const htmlContent = await this.templateInjectable.render(
|
const htmlContent = renderExportResourceTableTemplateHtml({
|
||||||
'modules/export-resource-table',
|
table: { rows, columns },
|
||||||
{
|
sheetTitle,
|
||||||
table: { rows, columns },
|
sheetDescription,
|
||||||
sheetTitle,
|
});
|
||||||
sheetDescription,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
// Convert the HTML content to PDF
|
// Convert the HTML content to PDF
|
||||||
return this.chromiumlyTenancy.convertHtmlContent(htmlContent, {
|
return this.chromiumlyTenancy.convertHtmlContent(htmlContent, {
|
||||||
margins: { top: 0.2, bottom: 0.2, left: 0.2, right: 0.2 },
|
margins: { top: 0.2, bottom: 0.2, left: 0.2, right: 0.2 },
|
||||||
|
|||||||
@@ -364,13 +364,18 @@ const TransLockingItemDesc = styled.p`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const TransLockingIcon = styled.div`
|
const TransLockingIcon = styled.div`
|
||||||
|
--x-text-color: #93a1ba;
|
||||||
|
|
||||||
|
.bp4-dark & {
|
||||||
|
--x-text-color: rgba(255, 255, 255, 0.6);
|
||||||
|
}
|
||||||
border: 1px solid var(--color-transaction-locking-item-icon-border);
|
border: 1px solid var(--color-transaction-locking-item-icon-border);
|
||||||
height: 45px;
|
height: 45px;
|
||||||
width: 45px;
|
width: 45px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 45px;
|
line-height: 45px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
color: #93a1ba;
|
color: var(--x-text-color);
|
||||||
|
|
||||||
.bp4-icon {
|
.bp4-icon {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -395,15 +400,24 @@ export const TransLockingContent = styled.div`
|
|||||||
|
|
||||||
export const TransLockingReason = styled.div`
|
export const TransLockingReason = styled.div`
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
--x-text-color: #777;
|
||||||
|
|
||||||
|
.bp4-dark & {
|
||||||
|
--x-text-color: rgba(255, 255, 255, 0.6);
|
||||||
|
}
|
||||||
strong {
|
strong {
|
||||||
color: #777;
|
color: var(--x-text-color);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const TransUnlockWrap = styled.div`
|
const TransUnlockWrap = styled.div`
|
||||||
|
-x-border-color: #ddd;
|
||||||
|
|
||||||
|
.bp4-dark & {
|
||||||
|
--x-border-color: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
border-top: 1px solid #ddd;
|
border-top: 1px solid var(--x-border-color);
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
|
||||||
${TransLockingReason} {
|
${TransLockingReason} {
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { x } from '@xstyled/emotion';
|
||||||
|
import { Box } from '../lib/layout/Box';
|
||||||
|
|
||||||
|
export interface ExportResourceTableColumn {
|
||||||
|
accessor: string;
|
||||||
|
name?: string;
|
||||||
|
style?: string;
|
||||||
|
group?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExportResourceTableCell {
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExportResourceTableRow {
|
||||||
|
cells: ExportResourceTableCell[];
|
||||||
|
classNames?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExportResourceTableTemplateProps {
|
||||||
|
sheetTitle?: string;
|
||||||
|
sheetDescription?: string;
|
||||||
|
table: {
|
||||||
|
columns: ExportResourceTableColumn[];
|
||||||
|
rows: ExportResourceTableRow[];
|
||||||
|
};
|
||||||
|
customCSS?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ExportResourceTableTemplate({
|
||||||
|
sheetTitle,
|
||||||
|
sheetDescription,
|
||||||
|
table,
|
||||||
|
customCSS,
|
||||||
|
}: ExportResourceTableTemplateProps) {
|
||||||
|
return (
|
||||||
|
<Box fontSize="12px" lineHeight="1.4" fontFamily='system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"'>
|
||||||
|
<Box p="20px">
|
||||||
|
{(sheetTitle || sheetDescription) && (
|
||||||
|
<Box mb="18px" className="sheet__title">
|
||||||
|
{sheetTitle && (
|
||||||
|
<x.h2 m={0} mb="10px" fontSize="16px" lineHeight="1" className="sheetTitle">
|
||||||
|
{sheetTitle}
|
||||||
|
</x.h2>
|
||||||
|
)}
|
||||||
|
{sheetDescription && (
|
||||||
|
<x.p m={0} className="sheetDesc">
|
||||||
|
{sheetDescription}
|
||||||
|
</x.p>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<x.table
|
||||||
|
className="sheet__table"
|
||||||
|
fontSize="inherit"
|
||||||
|
lineHeight="inherit"
|
||||||
|
w="100%"
|
||||||
|
tableLayout="auto"
|
||||||
|
borderCollapse="collapse"
|
||||||
|
>
|
||||||
|
<x.thead>
|
||||||
|
<x.tr>
|
||||||
|
{table.columns.map((column) => {
|
||||||
|
let styleObj: React.CSSProperties | undefined;
|
||||||
|
if (column.style) {
|
||||||
|
try {
|
||||||
|
// Handle style as JSON string
|
||||||
|
styleObj = JSON.parse(column.style);
|
||||||
|
} catch {
|
||||||
|
// If parsing fails, ignore the style
|
||||||
|
styleObj = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<x.th
|
||||||
|
key={column.accessor}
|
||||||
|
borderTop="1px solid #000"
|
||||||
|
borderBottom="1px solid #000"
|
||||||
|
bg="#fff"
|
||||||
|
p="4px"
|
||||||
|
lineHeight="1.2"
|
||||||
|
className={`column--${column.accessor}`}
|
||||||
|
style={styleObj}
|
||||||
|
>
|
||||||
|
{column.name || column.accessor}
|
||||||
|
</x.th>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</x.tr>
|
||||||
|
</x.thead>
|
||||||
|
<x.tbody>
|
||||||
|
{table.rows.map((row, rowIndex) => (
|
||||||
|
<x.tr key={rowIndex} className={row.classNames}>
|
||||||
|
{row.cells.map((cell) => (
|
||||||
|
<x.td
|
||||||
|
key={cell.key}
|
||||||
|
p="4px 8px"
|
||||||
|
borderBottom="1px solid #CCC"
|
||||||
|
className={`cell--${cell.key}`}
|
||||||
|
>
|
||||||
|
<span dangerouslySetInnerHTML={{ __html: cell.value }} />
|
||||||
|
</x.td>
|
||||||
|
))}
|
||||||
|
</x.tr>
|
||||||
|
))}
|
||||||
|
</x.tbody>
|
||||||
|
</x.table>
|
||||||
|
|
||||||
|
{customCSS && (
|
||||||
|
<x.style dangerouslySetInnerHTML={{ __html: customCSS }} />
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -4,9 +4,11 @@ export * from './components/EstimatePaperTemplate';
|
|||||||
export * from './components/ReceiptPaperTemplate';
|
export * from './components/ReceiptPaperTemplate';
|
||||||
export * from './components/PaymentReceivedPaperTemplate';
|
export * from './components/PaymentReceivedPaperTemplate';
|
||||||
export * from './components/FinancialSheetTemplate';
|
export * from './components/FinancialSheetTemplate';
|
||||||
|
export * from './components/ExportResourceTableTemplate';
|
||||||
|
|
||||||
export * from './renders/render-invoice-paper-template';
|
export * from './renders/render-invoice-paper-template';
|
||||||
export * from './renders/render-estimate-paper-template';
|
export * from './renders/render-estimate-paper-template';
|
||||||
export * from './renders/render-receipt-paper-template';
|
export * from './renders/render-receipt-paper-template';
|
||||||
export * from './renders/render-payment-received-paper-template';
|
export * from './renders/render-payment-received-paper-template';
|
||||||
export * from './renders/render-financial-sheet-template';
|
export * from './renders/render-financial-sheet-template';
|
||||||
|
export * from './renders/render-export-resource-table-template';
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import {
|
||||||
|
ExportResourceTableTemplate,
|
||||||
|
ExportResourceTableTemplateProps,
|
||||||
|
} from '../components/ExportResourceTableTemplate';
|
||||||
|
import { renderSSR } from './render-ssr';
|
||||||
|
|
||||||
|
export const renderExportResourceTableTemplateHtml = (
|
||||||
|
props: ExportResourceTableTemplateProps
|
||||||
|
) => {
|
||||||
|
return renderSSR(
|
||||||
|
<ExportResourceTableTemplate {...props} />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
Reference in New Issue
Block a user