mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-24 00:29:49 +00:00
feat: localization invoice, estimate and receipt pdf templates.
This commit is contained in:
@@ -37,4 +37,4 @@ LICENSES_AUTH_PASSWORD=root
|
|||||||
|
|
||||||
AGENDASH_AUTH_USER=agendash
|
AGENDASH_AUTH_USER=agendash
|
||||||
AGENDASH_AUTH_PASSWORD=123123
|
AGENDASH_AUTH_PASSWORD=123123
|
||||||
BROWSER_WS_ENDPOINT=ws://localhost:3000/
|
BROWSER_WS_ENDPOINT=ws://localhost:4080/
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
"copy-18n": "cpy --cwd=src/locales --parents '**/*.json' ../../build/locales",
|
"copy-18n": "cpy --cwd=src/locales --parents '**/*.json' ../../build/locales",
|
||||||
"clear": "rimraf build",
|
"clear": "rimraf build",
|
||||||
"build:ts": "tsc -p tsconfig.json",
|
"build:ts": "tsc -p tsconfig.json",
|
||||||
"build:resources": "gulp --gulpfile=scripts/gulpfile.js styles",
|
"build:resources": "gulp --gulpfile=scripts/gulpfile.js styles styles-rtl",
|
||||||
"build": "npm-run-all clear build:ts copy-18n"
|
"build": "npm-run-all clear build:ts copy-18n"
|
||||||
},
|
},
|
||||||
"author": "Ahmed Bouhuolia, <a.bouhuolia@gmail.com>",
|
"author": "Ahmed Bouhuolia, <a.bouhuolia@gmail.com>",
|
||||||
@@ -81,6 +81,7 @@
|
|||||||
"ramda": "^0.27.1",
|
"ramda": "^0.27.1",
|
||||||
"rate-limiter-flexible": "^2.1.14",
|
"rate-limiter-flexible": "^2.1.14",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
|
"rtl-detect": "^1.0.4",
|
||||||
"ts-transformer-keys": "^0.4.2",
|
"ts-transformer-keys": "^0.4.2",
|
||||||
"tsyringe": "^4.3.0",
|
"tsyringe": "^4.3.0",
|
||||||
"uniqid": "^5.2.0",
|
"uniqid": "^5.2.0",
|
||||||
@@ -102,13 +103,17 @@
|
|||||||
"eslint-plugin-import": "^2.19.1",
|
"eslint-plugin-import": "^2.19.1",
|
||||||
"faker": "^4.1.0",
|
"faker": "^4.1.0",
|
||||||
"getopts": "^2.2.5",
|
"getopts": "^2.2.5",
|
||||||
|
"gulp-postcss": "^9.0.0",
|
||||||
|
"gulp-rename": "^2.0.0",
|
||||||
"knex-factory": "0.0.6",
|
"knex-factory": "0.0.6",
|
||||||
|
"merge-stream": "^2.0.0",
|
||||||
"mocha": "^5.2.0",
|
"mocha": "^5.2.0",
|
||||||
"module-alias": "^2.2.2",
|
"module-alias": "^2.2.2",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"nyc": "^14.1.1",
|
"nyc": "^14.1.1",
|
||||||
"regenerator-runtime": "^0.13.7",
|
"regenerator-runtime": "^0.13.7",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
|
"rtlcss": "^3.3.0",
|
||||||
"sass": "^1.37.5",
|
"sass": "^1.37.5",
|
||||||
"sinon": "^7.4.2",
|
"sinon": "^7.4.2",
|
||||||
"ts-node": "^9.0.0",
|
"ts-node": "^9.0.0",
|
||||||
|
|||||||
552
server/resources/css/modules/estimate-rtl.css
Normal file
552
server/resources/css/modules/estimate-rtl.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
558
server/resources/css/modules/invoice-rtl.css
Normal file
558
server/resources/css/modules/invoice-rtl.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
552
server/resources/css/modules/receipt-rtl.css
Normal file
552
server/resources/css/modules/receipt-rtl.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -21,3 +21,15 @@ th {
|
|||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body{
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #212529;
|
||||||
|
background-color: #fff;
|
||||||
|
direction: ltr;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
26
server/resources/scss/fonts.scss
Normal file
26
server/resources/scss/fonts.scss
Normal file
File diff suppressed because one or more lines are too long
@@ -1,57 +1,18 @@
|
|||||||
@import "../base.scss";
|
@import "../base.scss";
|
||||||
|
@import "../fonts.scss";
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background: #f8f9fa;
|
background: #f8f9fa;
|
||||||
font-family: 'Noto Sans', sans-serif;
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
||||||
|
html[lang^='ar'] & {
|
||||||
|
font-family: "Segoe UI";
|
||||||
|
}
|
||||||
|
html[lang^='en'] & {
|
||||||
|
font-family: "Noto Sans";
|
||||||
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.page {
|
|
||||||
background: white;
|
|
||||||
display: block;
|
|
||||||
margin: 0.5cm auto;
|
|
||||||
box-shadow: rgba(122, 136, 146, 0.15) 0px 1px 3px 1px;
|
|
||||||
width: 21cm;
|
|
||||||
height: 29.7cm;
|
|
||||||
|
|
||||||
@media print {
|
|
||||||
margin: 0;
|
|
||||||
box-shadow: 0 0 0;
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[size="A4"] {
|
|
||||||
width: 21cm;
|
|
||||||
height: 29.7cm;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[size="A4"][layout="landscape"] {
|
|
||||||
width: 29.7cm;
|
|
||||||
height: 21cm;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[size="A3"] {
|
|
||||||
width: 29.7cm;
|
|
||||||
height: 42cm;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[size="A3"][layout="landscape"] {
|
|
||||||
width: 42cm;
|
|
||||||
height: 29.7cm;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[size="A5"] {
|
|
||||||
width: 14.8cm;
|
|
||||||
height: 21cm;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[size="A5"][layout="landscape"] {
|
|
||||||
width: 21cm;
|
|
||||||
height: 14.8cm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
.invoice{
|
.invoice{
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 45px;
|
padding: 45px 40px;
|
||||||
|
|
||||||
&__header{
|
&__header{
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
html
|
html(lang=locale)
|
||||||
head
|
head
|
||||||
title My Site - #{title}
|
title My Site - #{title}
|
||||||
block head
|
block head
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ extends ../PaperTemplateLayout.pug
|
|||||||
|
|
||||||
block head
|
block head
|
||||||
style
|
style
|
||||||
include ../../css/modules/estimate.css
|
if (isRtl)
|
||||||
|
include ../../css/modules/estimate-rtl.css
|
||||||
|
else
|
||||||
|
include ../../css/modules/estimate.css
|
||||||
|
|
||||||
block content
|
block content
|
||||||
div.estimate
|
div.estimate
|
||||||
@@ -18,7 +21,7 @@ block content
|
|||||||
|
|
||||||
div.estimate__meta
|
div.estimate__meta
|
||||||
div.estimate__meta-item.estimate__meta-item--amount
|
div.estimate__meta-item.estimate__meta-item--amount
|
||||||
span.label #{__('estimate.paper.due_amount')}
|
span.label #{__('estimate.paper.amount')}
|
||||||
span.value #{saleEstimate.formattedAmount}
|
span.value #{saleEstimate.formattedAmount}
|
||||||
|
|
||||||
div.estimate__meta-item.estimate__meta-item--billed-to
|
div.estimate__meta-item.estimate__meta-item--billed-to
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ extends ../PaperTemplateLayout.pug
|
|||||||
|
|
||||||
block head
|
block head
|
||||||
style
|
style
|
||||||
include ../../css/modules/invoice.css
|
if (isRtl)
|
||||||
|
include ../../css/modules/invoice-rtl.css
|
||||||
|
else
|
||||||
|
include ../../css/modules/invoice.css
|
||||||
|
|
||||||
block content
|
block content
|
||||||
div.invoice
|
div.invoice
|
||||||
@@ -19,7 +22,7 @@ block content
|
|||||||
|
|
||||||
div.invoice__meta
|
div.invoice__meta
|
||||||
div.invoice__meta-item.invoice__meta-item--amount
|
div.invoice__meta-item.invoice__meta-item--amount
|
||||||
span.label #{__('estimate.paper.due_amount')}
|
span.label #{__('invoice.paper.due_amount')}
|
||||||
span.value #{saleInvoice.formattedAmount}
|
span.value #{saleInvoice.formattedAmount}
|
||||||
|
|
||||||
div.invoice__meta-item.invoice__meta-item--billed-to
|
div.invoice__meta-item.invoice__meta-item--billed-to
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ extends ../PaperTemplateLayout.pug
|
|||||||
|
|
||||||
block head
|
block head
|
||||||
style
|
style
|
||||||
include ../../css/modules/receipt.css
|
if (isRtl)
|
||||||
|
include ../../css/modules/receipt-rtl.css
|
||||||
|
else
|
||||||
|
include ../../css/modules/receipt.css
|
||||||
|
|
||||||
block content
|
block content
|
||||||
div.receipt
|
div.receipt
|
||||||
|
|||||||
@@ -37,20 +37,20 @@ module.exports = {
|
|||||||
clean: ['style.css', 'style.min.css', 'style-rtl.css', 'style-rtl.min.css'],
|
clean: ['style.css', 'style.min.css', 'style-rtl.css', 'style-rtl.min.css'],
|
||||||
build: [
|
build: [
|
||||||
{
|
{
|
||||||
src: `${RESOURCES_PATH}/scss/modules/invoice.scss`, // Path to main .scss file.
|
src: `${RESOURCES_PATH}/scss/modules/invoice.scss`,
|
||||||
dest: `${RESOURCES_PATH}/css/modules`, // Path to place the compiled CSS file.
|
dest: `${RESOURCES_PATH}/css/modules`,
|
||||||
// sourcemaps: true, // Allow to enable/disable sourcemaps or pass object to configure it.
|
// sourcemaps: true, // Allow to enable/disable sourcemaps or pass object to configure it.
|
||||||
// minify: true, // Allow to enable/disable minify the source.
|
// minify: true, // Allow to enable/disable minify the source.
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: `${RESOURCES_PATH}/scss/modules/estimate.scss`, // Path to main .scss file.
|
src: `${RESOURCES_PATH}/scss/modules/estimate.scss`,
|
||||||
dest: `${RESOURCES_PATH}/css/modules`, // Path to place the compiled CSS file.
|
dest: `${RESOURCES_PATH}/css/modules`,
|
||||||
// sourcemaps: true, // Allow to enable/disable sourcemaps or pass object to configure it.
|
// sourcemaps: true, // Allow to enable/disable sourcemaps or pass object to configure it.
|
||||||
// minify: true, // Allow to enable/disable minify the source.
|
// minify: true, // Allow to enable/disable minify the source.
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: `${RESOURCES_PATH}/scss/modules/receipt.scss`, // Path to main .scss file.
|
src: `${RESOURCES_PATH}/scss/modules/receipt.scss`,
|
||||||
dest: `${RESOURCES_PATH}/css/modules`, // Path to place the compiled CSS file.
|
dest: `${RESOURCES_PATH}/css/modules`,
|
||||||
// sourcemaps: true, // Allow to enable/disable sourcemaps or pass object to configure it.
|
// sourcemaps: true, // Allow to enable/disable sourcemaps or pass object to configure it.
|
||||||
// minify: true, // Allow to enable/disable minify the source.
|
// minify: true, // Allow to enable/disable minify the source.
|
||||||
},
|
},
|
||||||
@@ -61,11 +61,19 @@ module.exports = {
|
|||||||
// minify: true,
|
// minify: true,
|
||||||
// },
|
// },
|
||||||
],
|
],
|
||||||
|
// RTL builds.
|
||||||
rtl: [
|
rtl: [
|
||||||
// RTL builds.
|
|
||||||
{
|
{
|
||||||
src: './style.css',
|
src: `${RESOURCES_PATH}/css/modules/invoice.css`,
|
||||||
dest: './', // The source files will be converted and suffixed to `-rtl` in this destination.
|
dest: `${RESOURCES_PATH}/css/modules`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: `${RESOURCES_PATH}/css/modules/estimate.css`,
|
||||||
|
dest: `${RESOURCES_PATH}/css/modules`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: `${RESOURCES_PATH}/css/modules/receipt.css`,
|
||||||
|
dest: `${RESOURCES_PATH}/css/modules`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,13 @@ const gulp = require('gulp');
|
|||||||
const sass = require('sass');
|
const sass = require('sass');
|
||||||
const gulpSass = require('gulp-sass')(sass); // Gulp pluign for Sass compilation.
|
const gulpSass = require('gulp-sass')(sass); // Gulp pluign for Sass compilation.
|
||||||
const mergeStream = require('merge-stream');
|
const mergeStream = require('merge-stream');
|
||||||
|
|
||||||
|
const rename = require('gulp-rename'); // Renames files E.g. style.css -> style.min.css
|
||||||
|
|
||||||
|
// Style related.
|
||||||
|
const postcss = require('gulp-postcss'); // Transforming styles with JS plugins
|
||||||
|
const rtlcss = require('rtlcss'); // Convert LTR CSS to RTL.
|
||||||
|
|
||||||
const config = require('./gulpConfig');
|
const config = require('./gulpConfig');
|
||||||
|
|
||||||
gulp.task('styles', () => {
|
gulp.task('styles', () => {
|
||||||
@@ -13,3 +20,31 @@ gulp.task('styles', () => {
|
|||||||
});
|
});
|
||||||
return mergeStream(builds);
|
return mergeStream(builds);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task: `styles-rtl`
|
||||||
|
*
|
||||||
|
* This task does the following.
|
||||||
|
* 1. Gets the source css files.
|
||||||
|
* 2. Covert LTR CSS to RTL.
|
||||||
|
* 3. Suffix all CSS files to `-rtl`.
|
||||||
|
* 4. Reloads css files via browser sync stream.
|
||||||
|
* 5. Combine matching media queries for `.min.css` version.
|
||||||
|
* 6. Minify all CSS files.
|
||||||
|
* 7. Reload minified css files via browser sync stream.
|
||||||
|
*/
|
||||||
|
gulp.task('styles-rtl', () => {
|
||||||
|
const builds = config.style.rtl.map((build) => {
|
||||||
|
return gulp
|
||||||
|
.src(build.src)
|
||||||
|
.pipe(
|
||||||
|
postcss([
|
||||||
|
rtlcss(config.style.rtlcss), // Convert LTR CSS to RTL.
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
.pipe(rename({ suffix: '-rtl' })) // Append "-rtl" to the filename.
|
||||||
|
.pipe(gulp.dest(build.dest));
|
||||||
|
});
|
||||||
|
|
||||||
|
return mergeStream(builds);
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from 'express';
|
||||||
import i18n from 'i18n';
|
import i18n from 'i18n';
|
||||||
|
import HasTenancyService from 'services/Tenancy/TenancyService';
|
||||||
|
import { injectI18nUtils } from './TenantDependencyInjection';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* I18n from organization settings.
|
* I18n from organization settings.
|
||||||
*/
|
*/
|
||||||
export default (req: Request, res: Response, next: NextFunction) => {
|
export default (req: Request, res: Response, next: NextFunction) => {
|
||||||
const Logger = Container.get('logger');
|
const Logger = Container.get('logger');
|
||||||
const { settings } = req;
|
const { settings, tenantId } = req;
|
||||||
|
|
||||||
if (!req.user) {
|
if (!req.user) {
|
||||||
throw new Error('Should load this middleware after `JWTAuth`.');
|
throw new Error('Should load this middleware after `JWTAuth`.');
|
||||||
@@ -16,9 +18,8 @@ export default (req: Request, res: Response, next: NextFunction) => {
|
|||||||
throw new Error('Should load this middleware after `SettingsMiddleware`.');
|
throw new Error('Should load this middleware after `SettingsMiddleware`.');
|
||||||
}
|
}
|
||||||
// Get the organization language from settings.
|
// Get the organization language from settings.
|
||||||
const language = settings.get({
|
const language = settings.get({ group: 'organization', key: 'language' });
|
||||||
group: 'organization', key: 'language',
|
|
||||||
});
|
|
||||||
if (language) {
|
if (language) {
|
||||||
i18n.setLocale(req, language);
|
i18n.setLocale(req, language);
|
||||||
}
|
}
|
||||||
@@ -26,5 +27,10 @@ export default (req: Request, res: Response, next: NextFunction) => {
|
|||||||
language,
|
language,
|
||||||
user: req.user,
|
user: req.user,
|
||||||
});
|
});
|
||||||
|
const tenantServices = Container.get(HasTenancyService);
|
||||||
|
const tenantContainer = tenantServices.tenantContainer(tenantId);
|
||||||
|
|
||||||
|
tenantContainer.set('i18n', injectI18nUtils(req));
|
||||||
|
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,15 +11,11 @@ export default async (req: Request, res: Response, next: NextFunction) => {
|
|||||||
if (tenantContainer && !tenantContainer.has('settings')) {
|
if (tenantContainer && !tenantContainer.has('settings')) {
|
||||||
const { settingRepository } = tenantContainer.get('repositories');
|
const { settingRepository } = tenantContainer.get('repositories');
|
||||||
|
|
||||||
Logger.info('[settings_middleware] initialize settings store.');
|
|
||||||
|
|
||||||
const settings = new SettingsStore(settingRepository);
|
const settings = new SettingsStore(settingRepository);
|
||||||
tenantContainer.set('settings', settings);
|
tenantContainer.set('settings', settings);
|
||||||
}
|
}
|
||||||
Logger.info('[settings_middleware] get settings instance from container.');
|
|
||||||
const settings = tenantContainer.get('settings');
|
const settings = tenantContainer.get('settings');
|
||||||
|
|
||||||
Logger.info('[settings_middleware] load settings from storage or cache.');
|
|
||||||
await settings.load();
|
await settings.load();
|
||||||
|
|
||||||
req.settings = settings;
|
req.settings = settings;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { ITenant } from 'interfaces';
|
|||||||
import { Request } from 'express';
|
import { Request } from 'express';
|
||||||
import TenancyService from 'services/Tenancy/TenancyService';
|
import TenancyService from 'services/Tenancy/TenancyService';
|
||||||
import TenantsManagerService from 'services/Tenancy/TenantsManager';
|
import TenantsManagerService from 'services/Tenancy/TenantsManager';
|
||||||
|
import rtlDetect from 'rtl-detect';
|
||||||
|
|
||||||
export default (req: Request, tenant: ITenant) => {
|
export default (req: Request, tenant: ITenant) => {
|
||||||
const { id: tenantId, organizationId } = tenant;
|
const { id: tenantId, organizationId } = tenant;
|
||||||
@@ -20,7 +21,7 @@ export default (req: Request, tenant: ITenant) => {
|
|||||||
|
|
||||||
const tenantContainer = tenantServices.tenantContainer(tenantId);
|
const tenantContainer = tenantServices.tenantContainer(tenantId);
|
||||||
|
|
||||||
tenantContainer.set('i18n', { __: req.__ });
|
tenantContainer.set('i18n', injectI18nUtils(req));
|
||||||
|
|
||||||
req.knex = knexInstance;
|
req.knex = knexInstance;
|
||||||
req.organizationId = organizationId;
|
req.organizationId = organizationId;
|
||||||
@@ -30,3 +31,17 @@ export default (req: Request, tenant: ITenant) => {
|
|||||||
req.repositories = repositories;
|
req.repositories = repositories;
|
||||||
req.cache = cacheInstance;
|
req.cache = cacheInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const injectI18nUtils =(req) => {
|
||||||
|
const locale = req.getLocale();
|
||||||
|
const direction = rtlDetect.getLangDir(locale);
|
||||||
|
|
||||||
|
return {
|
||||||
|
locale,
|
||||||
|
__: req.__,
|
||||||
|
direction,
|
||||||
|
isRtl: direction === 'rtl',
|
||||||
|
isLtr: direction === 'ltr',
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -160,5 +160,32 @@
|
|||||||
"Liabilities and Equity": "التزامات وحقوق الملكية",
|
"Liabilities and Equity": "التزامات وحقوق الملكية",
|
||||||
"Closing balance": "الرصيد الختامي",
|
"Closing balance": "الرصيد الختامي",
|
||||||
"Opening balance": "الرصيد الفتاحي",
|
"Opening balance": "الرصيد الفتاحي",
|
||||||
"Total {{accountName}}": "إجمالي {{accountName}}"
|
"Total {{accountName}}": "إجمالي {{accountName}}",
|
||||||
|
"invoice.paper.invoice": "فاتورة",
|
||||||
|
"invoice.paper.due_amount": "القيمة المستحقة",
|
||||||
|
"invoice.paper.billed_to": "فاتورة إلي",
|
||||||
|
"invoice.paper.invoice_date": "تاريخ الفاتورة",
|
||||||
|
"invoice.paper.invoice_number": "رقم الفاتورة",
|
||||||
|
"invoice.paper.due_date": "تاريخ الاستحقاق",
|
||||||
|
"invoice.paper.conditions_title": "الشروط والأحكام",
|
||||||
|
"invoice.paper.notes_title": "ملاحظات",
|
||||||
|
"item_entry.paper.item_name": "اسم الصنف",
|
||||||
|
"item_entry.paper.rate": "السعر",
|
||||||
|
"item_entry.paper.quantity": "الكمية",
|
||||||
|
"item_entry.paper.total": "إجمالي",
|
||||||
|
"estimate.paper.estimate": "عرض أسعار",
|
||||||
|
"estimate.paper.billed_to": "عرض أسعار إلي",
|
||||||
|
"estimate.paper.estimate_date": "تاريخ العرض",
|
||||||
|
"estimate.paper.estimate_number": "رقم العرض",
|
||||||
|
"estimate.paper.expiration_date": "تاريخ انتهاء الصلاحية",
|
||||||
|
"estimate.paper.conditions_title": "الشروط والأحكام",
|
||||||
|
"estimate.paper.notes_title": "ملاحظات",
|
||||||
|
"estimate.paper.amount": "قيمة العرض",
|
||||||
|
"receipt.paper.receipt": "إيصال",
|
||||||
|
"receipt.paper.billed_to": "الإيصال إلي",
|
||||||
|
"receipt.paper.receipt_date": "تاريخ الإيصال",
|
||||||
|
"receipt.paper.receipt_number": "رقم الإيصال",
|
||||||
|
"receipt.paper.conditions_title": "الشروط والأحكام",
|
||||||
|
"receipt.paper.notes_title": "ملاحظات",
|
||||||
|
"receipt.paper.receipt_amount": "قيمة الإيصال"
|
||||||
}
|
}
|
||||||
@@ -161,6 +161,7 @@
|
|||||||
"Opening Balance": "Opening balance",
|
"Opening Balance": "Opening balance",
|
||||||
"Total {{accountName}}": "Total {{accountName}}",
|
"Total {{accountName}}": "Total {{accountName}}",
|
||||||
"invoice.paper.invoice": "Invoice",
|
"invoice.paper.invoice": "Invoice",
|
||||||
|
"invoice.paper.due_amount": "Due amount",
|
||||||
"invoice.paper.billed_to": "Billed to",
|
"invoice.paper.billed_to": "Billed to",
|
||||||
"invoice.paper.invoice_date": "Invoice date",
|
"invoice.paper.invoice_date": "Invoice date",
|
||||||
"invoice.paper.invoice_number": "Invoice No.",
|
"invoice.paper.invoice_number": "Invoice No.",
|
||||||
@@ -178,7 +179,7 @@
|
|||||||
"estimate.paper.expiration_date": "Expiration date",
|
"estimate.paper.expiration_date": "Expiration date",
|
||||||
"estimate.paper.conditions_title": "Conditions & terms",
|
"estimate.paper.conditions_title": "Conditions & terms",
|
||||||
"estimate.paper.notes_title": "Notes",
|
"estimate.paper.notes_title": "Notes",
|
||||||
"estimate.paper.due_amount": "Due amount",
|
"estimate.paper.amount": "Estimate amount",
|
||||||
"receipt.paper.receipt": "Receipt",
|
"receipt.paper.receipt": "Receipt",
|
||||||
"receipt.paper.billed_to": "Billed to",
|
"receipt.paper.billed_to": "Billed to",
|
||||||
"receipt.paper.receipt_date": "Receipt date",
|
"receipt.paper.receipt_date": "Receipt date",
|
||||||
|
|||||||
Reference in New Issue
Block a user