Add QR IBAN

This commit is contained in:
Hillel Coren 2022-06-30 09:32:28 +03:00
parent 3cf9cbdfac
commit a222e93d0d
7 changed files with 277 additions and 162 deletions

View File

@ -171,6 +171,7 @@ const String kCurrencyEuro = '3';
const String kCountryUnitedStates = '840';
const String kCountryCanada = '124';
const String kCountrySwitzerland = '756';
const String kInvoiceStatusViewed = '-3';
const String kInvoiceStatusUnpaid = '-2';

View File

@ -619,6 +619,8 @@ abstract class CompanyEntity extends Object
String get currencyId => settings.currencyId ?? kDefaultCurrencyId;
bool get supportsQrIban => settings.countryId == kCountrySwitzerland;
// ignore: unused_element
static void _initializeBuilder(CompanyEntityBuilder builder) => builder
..calculateExpenseTaxByAmount = false

View File

@ -885,6 +885,14 @@ abstract class SettingsEntity
@BuiltValueField(wireName: 'purchase_order_number_counter')
int get purchaseOrderNumberCounter;
@nullable
@BuiltValueField(wireName: 'qr_iban')
String get qrIban;
@nullable
@BuiltValueField(wireName: 'besr_id')
String get besrId;
bool get hasAddress => address1 != null && address1.isNotEmpty;
bool get hasLogo => companyLogo != null && companyLogo.isNotEmpty;

File diff suppressed because one or more lines are too long

View File

@ -78,6 +78,8 @@ class _CompanyDetailsState extends State<CompanyDetails>
final _creditFooterController = TextEditingController();
final _purchaseOrderTermsController = TextEditingController();
final _purchaseOrderFooterController = TextEditingController();
final _qrIbanController = TextEditingController();
final _besrIdController = TextEditingController();
List<TextEditingController> _controllers = [];
@ -126,6 +128,8 @@ class _CompanyDetailsState extends State<CompanyDetails>
_creditTermsController,
_purchaseOrderFooterController,
_purchaseOrderTermsController,
_qrIbanController,
_besrIdController,
];
_controllers.forEach(
@ -157,6 +161,8 @@ class _CompanyDetailsState extends State<CompanyDetails>
_creditTermsController.text = settings.defaultCreditTerms;
_purchaseOrderFooterController.text = settings.defaultPurchaseOrderFooter;
_purchaseOrderTermsController.text = settings.defaultPurchaseOrderTerms;
_qrIbanController.text = settings.qrIban;
_besrIdController.text = settings.besrId;
_controllers.forEach(
(dynamic controller) => controller.addListener(_onSettingsChanged));
@ -200,7 +206,9 @@ class _CompanyDetailsState extends State<CompanyDetails>
..defaultCreditFooter = _creditFooterController.text.trim()
..defaultCreditTerms = _creditTermsController.text.trim()
..defaultPurchaseOrderFooter = _purchaseOrderFooterController.text.trim()
..defaultPurchaseOrderTerms = _purchaseOrderTermsController.text.trim());
..defaultPurchaseOrderTerms = _purchaseOrderTermsController.text.trim()
..qrIban = _qrIbanController.text.trim()
..besrId = _besrIdController.text.trim());
if (settings != widget.viewModel.settings) {
_debouncer.run(() {
widget.viewModel.onSettingsChanged(settings);
@ -323,6 +331,23 @@ class _CompanyDetailsState extends State<CompanyDetails>
),
],
),
if (company.supportsQrIban)
FormCard(
children: [
DecoratedFormField(
label: localization.qrIban,
controller: _qrIbanController,
onSavePressed: viewModel.onSavePressed,
keyboardType: TextInputType.text,
),
DecoratedFormField(
label: localization.besrId,
controller: _besrIdController,
onSavePressed: viewModel.onSavePressed,
keyboardType: TextInputType.text,
),
],
),
if (!state.settingsUIState.isFiltered)
FormCard(
isLast: true,

View File

@ -62,10 +62,25 @@ class _InvoiceDesignState extends State<InvoiceDesign>
@override
void initState() {
super.initState();
final settingsUIState = widget.viewModel.state.settingsUIState;
final state = widget.viewModel.state;
final settingsUIState = state.settingsUIState;
_focusNode = FocusScopeNode();
int tabs = 6;
[
EntityType.invoice,
EntityType.quote,
EntityType.credit,
EntityType.task,
].forEach((entityType) {
if (state.company.isModuleEnabled(entityType)) {
tabs++;
}
});
_controller = TabController(
vsync: this, length: 10, initialIndex: settingsUIState.tabIndex);
vsync: this, length: tabs, initialIndex: settingsUIState.tabIndex);
_controller.addListener(_onTabChanged);
}
@ -110,11 +125,15 @@ class _InvoiceDesignState extends State<InvoiceDesign>
Tab(text: localization.clientDetails),
Tab(text: localization.companyDetails),
Tab(text: localization.companyAddress),
Tab(text: localization.invoiceDetails),
Tab(text: localization.quoteDetails),
Tab(text: localization.creditDetails),
if (company.isModuleEnabled(EntityType.invoice))
Tab(text: localization.invoiceDetails),
if (company.isModuleEnabled(EntityType.quote))
Tab(text: localization.quoteDetails),
if (company.isModuleEnabled(EntityType.credit))
Tab(text: localization.creditDetails),
Tab(text: localization.productColumns),
Tab(text: localization.taskColumns),
if (company.isModuleEnabled(EntityType.task))
Tab(text: localization.taskColumns),
Tab(text: localization.totalFields),
],
),
@ -579,119 +598,123 @@ class _InvoiceDesignState extends State<InvoiceDesign>
prefix: 'company',
),
),
FormCard(
isLast: true,
child: MultiSelectList(
options: [
...[
if (company.isModuleEnabled(EntityType.invoice))
FormCard(
isLast: true,
child: MultiSelectList(
options: [
...[
InvoiceFields.number,
InvoiceFields.poNumber,
InvoiceFields.date,
InvoiceFields.dueDate,
InvoiceFields.amount,
InvoiceFields.balance,
InvoiceFields.balanceDue,
InvoiceFields.customValue1,
InvoiceFields.customValue2,
InvoiceFields.customValue3,
InvoiceFields.customValue4,
InvoiceFields.project,
InvoiceFields.vendor,
].map((field) => '\$invoice.$field'),
...[
ClientFields.balance,
].map((field) => '\$client.$field')
],
defaultSelected: [
InvoiceFields.number,
InvoiceFields.poNumber,
InvoiceFields.date,
InvoiceFields.dueDate,
InvoiceFields.amount,
InvoiceFields.balance,
InvoiceFields.total,
InvoiceFields.balanceDue,
InvoiceFields.customValue1,
InvoiceFields.customValue2,
InvoiceFields.customValue3,
InvoiceFields.customValue4,
InvoiceFields.project,
InvoiceFields.vendor,
].map((field) => '\$invoice.$field'),
...[
ClientFields.balance,
].map((field) => '\$client.$field')
],
defaultSelected: [
InvoiceFields.number,
InvoiceFields.poNumber,
InvoiceFields.date,
InvoiceFields.dueDate,
InvoiceFields.total,
InvoiceFields.balanceDue,
].map((field) => '\$invoice.$field').toList(),
selected: settings.getFieldsForSection(kPdfFieldsInvoiceDetails),
onSelected: (values) {
viewModel.onSettingsChanged(settings.setFieldsForSection(
kPdfFieldsInvoiceDetails, values));
},
addTitle: localization.addField,
liveChanges: true,
prefix: 'invoice',
].map((field) => '\$invoice.$field').toList(),
selected:
settings.getFieldsForSection(kPdfFieldsInvoiceDetails),
onSelected: (values) {
viewModel.onSettingsChanged(settings.setFieldsForSection(
kPdfFieldsInvoiceDetails, values));
},
addTitle: localization.addField,
liveChanges: true,
prefix: 'invoice',
),
),
),
FormCard(
isLast: true,
child: MultiSelectList(
options: [
...[
if (company.isModuleEnabled(EntityType.quote))
FormCard(
isLast: true,
child: MultiSelectList(
options: [
...[
QuoteFields.number,
QuoteFields.poNumber,
QuoteFields.date,
QuoteFields.validUntil,
QuoteFields.total,
QuoteFields.customValue1,
QuoteFields.customValue2,
QuoteFields.customValue3,
QuoteFields.customValue4,
].map((field) => '\$quote.$field'),
...[
ClientFields.balance,
].map((field) => '\$client.$field')
],
defaultSelected: [
QuoteFields.number,
QuoteFields.poNumber,
QuoteFields.date,
QuoteFields.validUntil,
QuoteFields.total,
QuoteFields.customValue1,
QuoteFields.customValue2,
QuoteFields.customValue3,
QuoteFields.customValue4,
].map((field) => '\$quote.$field'),
...[
ClientFields.balance,
].map((field) => '\$client.$field')
],
defaultSelected: [
QuoteFields.number,
QuoteFields.poNumber,
QuoteFields.date,
QuoteFields.validUntil,
QuoteFields.total,
].map((field) => '\$quote.$field').toList(),
selected: settings.getFieldsForSection(kPdfFieldsQuoteDetails),
onSelected: (values) {
viewModel.onSettingsChanged(settings.setFieldsForSection(
kPdfFieldsQuoteDetails, values));
},
addTitle: localization.addField,
liveChanges: true,
prefix: 'quote',
].map((field) => '\$quote.$field').toList(),
selected: settings.getFieldsForSection(kPdfFieldsQuoteDetails),
onSelected: (values) {
viewModel.onSettingsChanged(settings.setFieldsForSection(
kPdfFieldsQuoteDetails, values));
},
addTitle: localization.addField,
liveChanges: true,
prefix: 'quote',
),
),
),
FormCard(
isLast: true,
child: MultiSelectList(
options: [
...[
if (company.isModuleEnabled(EntityType.credit))
FormCard(
isLast: true,
child: MultiSelectList(
options: [
...[
CreditFields.number,
CreditFields.poNumber,
CreditFields.date,
CreditFields.total,
CreditFields.balance,
CreditFields.customValue1,
CreditFields.customValue2,
CreditFields.customValue3,
CreditFields.customValue4,
].map((field) => '\$credit.$field'),
...[
ClientFields.balance,
].map((field) => '\$client.$field')
],
defaultSelected: [
CreditFields.number,
CreditFields.poNumber,
CreditFields.date,
CreditFields.total,
CreditFields.balance,
CreditFields.customValue1,
CreditFields.customValue2,
CreditFields.customValue3,
CreditFields.customValue4,
].map((field) => '\$credit.$field'),
...[
ClientFields.balance,
].map((field) => '\$client.$field')
],
defaultSelected: [
CreditFields.number,
CreditFields.poNumber,
CreditFields.date,
CreditFields.balance,
CreditFields.total,
].map((field) => '\$credit.$field').toList(),
selected: settings.getFieldsForSection(kPdfFieldsCreditDetails),
onSelected: (values) {
viewModel.onSettingsChanged(settings.setFieldsForSection(
kPdfFieldsCreditDetails, values));
},
addTitle: localization.addField,
liveChanges: true,
prefix: 'credit',
CreditFields.total,
].map((field) => '\$credit.$field').toList(),
selected: settings.getFieldsForSection(kPdfFieldsCreditDetails),
onSelected: (values) {
viewModel.onSettingsChanged(settings.setFieldsForSection(
kPdfFieldsCreditDetails, values));
},
addTitle: localization.addField,
liveChanges: true,
prefix: 'credit',
),
),
),
FormCard(
isLast: true,
child: MultiSelectList(
@ -728,42 +751,43 @@ class _InvoiceDesignState extends State<InvoiceDesign>
prefix: 'product',
),
),
FormCard(
isLast: true,
child: MultiSelectList(
options: [
TaskItemFields.service,
TaskItemFields.description,
TaskItemFields.hours,
TaskItemFields.rate,
if (company.hasItemTaxes) TaskItemFields.tax,
if (company.enableProductDiscount) TaskItemFields.discount,
TaskItemFields.lineTotal,
TaskItemFields.custom1,
TaskItemFields.custom2,
TaskItemFields.custom3,
TaskItemFields.custom4,
TaskItemFields.grossLineTotal,
].map((field) => '\$task.$field').toList(),
defaultSelected: [
TaskItemFields.service,
TaskItemFields.description,
TaskItemFields.rate,
TaskItemFields.hours,
if (company.enableProductDiscount) TaskItemFields.discount,
if (company.hasItemTaxes) TaskItemFields.tax,
TaskItemFields.lineTotal,
].map((field) => '\$task.$field').toList(),
selected: settings.getFieldsForSection(kPdfFieldsTaskColumns),
onSelected: (values) {
viewModel.onSettingsChanged(settings.setFieldsForSection(
kPdfFieldsTaskColumns, values));
},
addTitle: localization.addField,
liveChanges: true,
prefix: 'task',
if (company.isModuleEnabled(EntityType.task))
FormCard(
isLast: true,
child: MultiSelectList(
options: [
TaskItemFields.service,
TaskItemFields.description,
TaskItemFields.hours,
TaskItemFields.rate,
if (company.hasItemTaxes) TaskItemFields.tax,
if (company.enableProductDiscount) TaskItemFields.discount,
TaskItemFields.lineTotal,
TaskItemFields.custom1,
TaskItemFields.custom2,
TaskItemFields.custom3,
TaskItemFields.custom4,
TaskItemFields.grossLineTotal,
].map((field) => '\$task.$field').toList(),
defaultSelected: [
TaskItemFields.service,
TaskItemFields.description,
TaskItemFields.rate,
TaskItemFields.hours,
if (company.enableProductDiscount) TaskItemFields.discount,
if (company.hasItemTaxes) TaskItemFields.tax,
TaskItemFields.lineTotal,
].map((field) => '\$task.$field').toList(),
selected: settings.getFieldsForSection(kPdfFieldsTaskColumns),
onSelected: (values) {
viewModel.onSettingsChanged(settings.setFieldsForSection(
kPdfFieldsTaskColumns, values));
},
addTitle: localization.addField,
liveChanges: true,
prefix: 'task',
),
),
),
FormCard(
isLast: true,
child: MultiSelectList(

View File

@ -16,6 +16,8 @@ mixin LocalizationsProvider on LocaleCodeAware {
static final Map<String, Map<String, String>> _localizedValues = {
'en': {
// STARTER: lang key - do not remove comment
'qr_iban': 'QR IBAN',
'besr_id': 'BESR ID',
'accept': 'Accept',
'clone_to_purchase_order': 'Clone to PO',
'vendor_email_not_set': 'Vendor does not have an email address set',
@ -70820,6 +70822,15 @@ mixin LocalizationsProvider on LocaleCodeAware {
_localizedValues[localeCode]['accept'] ??
_localizedValues['en']['accept'];
String get qrIban =>
_localizedValues[localeCode]['qr_iban'] ??
_localizedValues['en']['qr_iban'];
String get besrId =>
_localizedValues[localeCode]['besr_id'] ??
_localizedValues['en']['besr_id'];
// STARTER: lang field - do not remove comment
String lookup(String key) {