frappe / erpnext

Free and Open Source Enterprise Resource Planning (ERP)
https://erpnext.com
GNU General Public License v3.0
21.3k stars 7.26k forks source link

MultiCurrency - Can't invoice customer #31193

Closed rtdany10 closed 2 years ago

rtdany10 commented 2 years ago

Information about bug

On first invoice of a new customer, if the currency is different from the ledger currency, system throws error: Party Account <account name here> currency and document currency should be same

Caused by https://github.com/frappe/erpnext/commit/80c85dd17cf0c0fdcf07d2e0c2151b2852a0c611

Module

accounts

Version

ERPNext: v13.31.1 (HEAD) Frappe Framework: v13.30.0 (HEAD)

Installation method

FrappeCloud

Relevant log output / Stack trace / Full Error Message.

Traceback (most recent call last):
  File "apps/frappe/frappe/app.py", line 69, in application
    response = frappe.api.handle()
  File "apps/frappe/frappe/api.py", line 55, in handle
    return frappe.handler.handle()
  File "apps/frappe/frappe/handler.py", line 38, in handle
    data = execute_cmd(cmd)
  File "apps/frappe/frappe/handler.py", line 76, in execute_cmd
    return frappe.call(method, **frappe.form_dict)
  File "apps/frappe/frappe/__init__.py", line 1448, in call
    return fn(*args, **newargs)
  File "apps/frappe/frappe/desk/form/save.py", line 25, in savedocs
    doc.save()
  File "apps/frappe/frappe/model/document.py", line 310, in save
    return self._save(*args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 332, in _save
    return self.insert()
  File "apps/frappe/frappe/model/document.py", line 261, in insert
    self.run_before_save_methods()
  File "apps/frappe/frappe/model/document.py", line 1052, in run_before_save_methods
    self.run_method("validate")
  File "apps/frappe/frappe/model/document.py", line 941, in run_method
    out = Document.hook(fn)(self, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1260, in composer
    return composed(self, method, *args, **kwargs)
  File "apps/frappe/frappe/model/document.py", line 1242, in runner
    add_to_return_value(self, fn(self, *args, **kwargs))
  File "apps/frappe/frappe/model/document.py", line 938, in fn
    return method_object(*args, **kwargs)
  File "apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.py", line 96, in validate
    super(SalesInvoice, self).validate()
  File "apps/erpnext/erpnext/controllers/selling_controller.py", line 32, in validate
    super(SellingController, self).validate()
  File "apps/erpnext/erpnext/controllers/stock_controller.py", line 38, in validate
    super(StockController, self).validate()
  File "apps/erpnext/erpnext/controllers/accounts_controller.py", line 173, in validate
    self.validate_party_account_currency()
  File "apps/erpnext/erpnext/controllers/accounts_controller.py", line 1467, in validate_party_account_currency
    frappe.bold(party_account)
  File "apps/frappe/frappe/__init__.py", line 511, in throw
    as_list=as_list,
  File "apps/frappe/frappe/__init__.py", line 479, in msgprint
    _raise_exception()
  File "apps/frappe/frappe/__init__.py", line 434, in _raise_exception
    raise raise_exception(msg)
frappe.exceptions.ValidationError: Party Account <b>Removed - R</b> currency and document currency should be same
rtdany10 commented 2 years ago

@deepeshgarg007 please look into this

dj12djdjs commented 2 years ago

This looks intentional by this PR: https://github.com/frappe/erpnext/pull/26916

It makes sense to maintain separate accounts if the customer/supplier uses multi currency.

Example: Customer A This customer will be billed in the base currency. (CAD)

Customer A - USD This customer will not use the default receivable account but a receivable account in the USD currency.

Is there a case this approach isn't valid ?

rtdany10 commented 2 years ago

This looks intentional by this PR: #26916

It makes sense to maintain separate accounts if the customer/supplier uses multi currency.

Yes, it's an intentional change. Although I disagree to keeping separate accounts for multi-currency. Why the need?

Example: Customer A This customer will be billed in the base currency. (CAD)

Customer A - USD This customer will not use the default receivable account but a receivable account in the USD currency.

Is there a case this approach isn't valid ?

You mean splitting the customer based on currency and setting defaults for each? I have customers who deal in 4 or 5 currencies. Splitting them would make reports like Accounts Receivable/Payable, General Ledger etc useless. ERP is meant to ease up things :disappointed:

This is a big change, and should have been optional, maybe a checkbox in Accounts Settings.

dj12djdjs commented 2 years ago

I have customers who deal in 4 or 5 currencies. Splitting them would make reports like Accounts Receivable/Payable, General Ledger etc useless.

Since the beginning of using ERP we have a separate account for all customers/suppliers for each currency they bill or we bill them with.

I've not tried using a single party account to book invoices against multiple currencies, I'd like to test this out. In my head I'm thinking it would be more difficult. My reasonings are:

Let's say the company base currency is USD and so is the receivables account currency. Invoice # Currency Exc. Debit Credit debit_in_account_currency (USD) credit_in_account_currency (USD)
0001 EUR 1.07 300.00 0.0 321.00 0.0
0002 GBP 1.26 76.50 0.0 96.39 0.00
0003 CAD 0.80 100 0.0 80.00 0.00

I've not tested this, but I'm thinking ERP will generate the Accounts receivable report in USD because that is currency of the receivable account. Therefor a statement will be sent to the customer owing a balance of $497.39 USD.

This surely should not be correct, you'll want to collect in the currency being billed. Not the currency of the receivable account.

This is my thoughts. I'm hoping I can test this out some time tomorrow. I'm curious to see how it actually works in the system.

rtdany10 commented 2 years ago

I've not tested this, but I'm thinking ERP will generate the Accounts receivable report in USD because that is currency of the receivable account. Therefor a statement will be sent to the customer owing a balance of $497.39 USD.

This surely should not be correct, you'll want to collect in the currency being billed. Not the currency of the receivable account.

Accounts Receivable report doesn't show currency, it shows only figures.

dj12djdjs commented 2 years ago

I've setup a test where the base currency of the company is USD I've also setup a customer setup on the default receivable account. (Also USD)

I've added the below invoices exactly.

Invoice # Currency Exc. Debit Credit debit_in_account_currency (USD) credit_in_account_currency (USD)
0001 EUR 1.07 300.00 0.0 321.00 0.0
0002 GBP 1.26 76.50 0.0 96.39 0.00
0003 CAD 0.80 100 0.0 80.00 0.00

image

In the first invoice you will see it is booked as € 300.00 and the company currency is booked as $ 321.00. So, we've billed the customer € 300.00 as such they should pay in Euro. image

Now, let's check the customer statement. image It is shows in USD instead of the billed currency of EUR.

Now, let's check the GL (EUR) balances You will see the amount is € 1.07 off balance. image

I think if ERPNext wanted to use this method of billing multiple currencies, the whole multi-currency system will need to be re-written as there are currently too many bugs with this approach.

This is why I opted to create individual Receivable/Payable accounts for my parties that use many currencies.

Still maybe @deepeshgarg007 can weigh in.

Solufyin commented 2 years ago

Hello @rtdany10,

As per your need we added generic solution for to segregated account receivable entries currency wise in Report. See the Reference : #31278

@nextchamp-saqib I hope it will be helpful for all ERPNext community.

Thanks

dj12djdjs commented 2 years ago

@Solufyin As per my understanding this won't solve the issue.

The account currency in @rtdany10 scenario will always be the company base currency for example INR. Therefor, filtering by currency on the accounts receivable report won't be effective as there is only 1 accounts receivable account.

I believe if we want to implement this, the accounts receivable report should show the document billed currency and not the converted amount booked in the receivable account. Even that approach might not be legal, as it is not the "officially" booked amount in the ledger. Probably best to consult an accountant on the matter.

rtdany10 commented 2 years ago

I am okay with this change and have no issues because I was able to convince my clients to change to the new flow of billing, but my concern arises of how such disruptive changes are pushed without communicating it with the community in prior.

When my client raised the issue, my support team couldn't understand the reason behind the issue, because it worked without any issue on their dev instance. By the time the issue was escalated and the developer team was assigned to it, the client had lost a business day. We then had to meet with their accounts team, explain the scenario and had them create separate ledgers.

I hope future changes like these are communicated with the community so that we can prepare ourselves and clients beforehand.

@dj12djdjs @deepeshgarg007 @Solufyin

deepeshgarg007 commented 2 years ago

@dj12djdjs Thank you for explaining the issues exactly in a detailed manner. To add to it as you have already pointed out ERPNext is not yet designed to handle multiple currencies for the same account, all the financial reports are built based on GLEs, and when invoicing is done in the company's account currency that multicurrency value with that exact exchange rate never goes to the GLE

This was only allowed for backward compatibility when multicurrency was introduced for the first time. This had to be stopped at some point, so we decided to do this for the newly created customer masters to soften the blow.

@rtdany10 Point well taken, further, we will communicate beforehand pushing such changes. I will close this issue now

barredterra commented 2 years ago

@deepeshgarg007

we decided to do this for the newly created customer masters to soften the blow

Good intentions, but this means that staff will need to remember at what point in time a party was created to choose the correct procedure. To do this change in a major release would have been more appropriate.

Apart from that, I don't see the problem that “had to be stopped”. We've been entering Purchase Invoices in foreign currencies for a while now. Accounting happens in our company currency only. The GL Entries and AP report show the correct value in our company currency.

Basically, we've been able to enter line items in invoice currency, while accounting in company currency only. ERPNext would convert the totals to company currency and create correct GL Entries. This is no longer possible now.

Feel free to reach out for a detailed explanation / proof that our scenario worked before this change.

Purchase Invoice Entered in USD (invoice currency), accounting happened flawlessly using the "base" totals in company currency. ```json { "name": "PINV-0001", "owner": "accounting@alyf.de", "creation": "2022-06-15 12:57:54.608329", "modified": "2022-06-15 12:58:38.626595", "modified_by": "accounting@alyf.de", "idx": 0, "docstatus": 1, "title": "Supplier Ltd", "naming_series": "ER-", "supplier": "Supplier Ltd", "supplier_name": "Supplier Ltd", "tax_id": "EU372001951", "due_date": "2022-06-29", "needs_manual_payment": 0, "company": "ALYF GmbH", "posting_date": "2022-06-15", "posting_time": "12:58:38.765367", "set_posting_time": 0, "is_paid": 0, "is_return": 0, "apply_tds": 0, "bill_no": "AT-9999999", "bill_date": "2022-06-01", "shipping_address": "ALYF GmbH-Billing", "shipping_address_display": "Peterssteinweg 14
\n04107 Leipzig
", "billing_address": "ALYF GmbH-Billing", "billing_address_display": "Peterssteinweg 14
\n04107 Leipzig
", "currency": "USD", "conversion_rate": 0.958257, "buying_price_list": "Standard EUR", "price_list_currency": "EUR", "plc_conversion_rate": 1, "ignore_pricing_rule": 0, "is_subcontracted": "No", "update_stock": 0, "total_qty": 8, "base_total": 57.5, "base_net_total": 57.5, "total_net_weight": 0, "total": 60, "net_total": 60, "tax_category": "Reverse Charge", "taxes_and_charges": "VAT payable 19% and deductable 19%", "base_taxes_and_charges_added": 10.92, "base_taxes_and_charges_deducted": 10.92, "base_total_taxes_and_charges": 0, "taxes_and_charges_added": 11.4, "taxes_and_charges_deducted": 11.4, "total_taxes_and_charges": 0, "apply_discount_on": "Grand Total", "base_discount_amount": 0, "additional_discount_percentage": 0, "discount_amount": 0, "base_grand_total": 57.5, "base_rounding_adjustment": 0, "base_rounded_total": 0, "grand_total": 60, "rounding_adjustment": 0, "rounded_total": 0, "total_advance": 0, "outstanding_amount": 57.5, "disable_rounded_total": 1, "paid_amount": 0, "base_paid_amount": 0, "write_off_amount": 0, "base_write_off_amount": 0, "allocate_advances_automatically": 0, "ignore_default_payment_terms_template": 0, "letter_head": "ALYF GmbH", "group_same_items": 0, "language": "en", "on_hold": 0, "status": "Unpaid", "is_internal_supplier": 0, "credit_to": "Accounts Payable EUR", "party_account_currency": "EUR", "is_opening": "No", "against_expense_account": "Other operating expense EUR", "remarks": "Against Supplier Invoice AT-9999999 dated 01.06.2022", "per_received": 0, "doctype": "Purchase Invoice", "items": [ { "name": "8e8a236e44", "owner": "accounting@alyf.de", "creation": "2022-06-15 12:57:54.608329", "modified": "2022-06-15 12:58:38.626595", "modified_by": "accounting@alyf.de", "parent": "PINV-0001", "parentfield": "items", "parenttype": "Purchase Invoice", "idx": 1, "docstatus": 1, "item_code": "439", "item_name": "Some Item", "description": "Some Item", "item_group": "All Item Groups", "image": "", "received_qty": 0, "qty": 8, "rejected_qty": 0, "uom": "User-Months", "conversion_factor": 1, "stock_uom": "User-Months", "stock_qty": 8, "price_list_rate": 0, "base_price_list_rate": 0, "margin_type": "", "margin_rate_or_amount": 0, "rate_with_margin": 0, "discount_percentage": 0, "discount_amount": 0, "base_rate_with_margin": 0, "rate": 7.5, "amount": 60, "base_rate": 7.19, "base_amount": 57.5, "stock_uom_rate": 7.5, "is_free_item": 0, "net_rate": 7.5, "net_amount": 60, "base_net_rate": 7.19, "base_net_amount": 57.5, "valuation_rate": 0, "item_tax_amount": 0, "landed_cost_voucher_amount": 0, "rm_supp_cost": 0, "expense_account": "Other operating expense EUR", "is_fixed_asset": 0, "enable_deferred_expense": 0, "allow_zero_valuation_rate": 0, "item_tax_rate": "{}", "include_exploded_items": 0, "weight_per_unit": 0, "total_weight": 0, "cost_center": "Main - ALYFG", "page_break": 0, "doctype": "Purchase Invoice Item" } ], "pricing_rules": [], "supplied_items": [], "taxes": [ { "name": "b899dd3c93", "owner": "accounting@alyf.de", "creation": "2022-06-15 12:57:54.608329", "modified": "2022-06-15 12:58:38.626595", "modified_by": "accounting@alyf.de", "parent": "PINV-0001", "parentfield": "taxes", "parenttype": "Purchase Invoice", "idx": 1, "docstatus": 1, "category": "Total", "add_deduct_tax": "Add", "charge_type": "On Net Total", "included_in_print_rate": 0, "included_in_paid_amount": 0, "account_head": "Deductible VAT", "description": "Deductible VAT", "rate": 19, "cost_center": "Main - ALYFG", "account_currency": "EUR", "tax_amount": 11.4, "tax_amount_after_discount_amount": 11.4, "total": 71.4, "base_tax_amount": 10.92, "base_total": 68.42, "base_tax_amount_after_discount_amount": 10.92, "doctype": "Purchase Taxes and Charges" }, { "name": "f45b86ada2", "owner": "accounting@alyf.de", "creation": "2022-06-15 12:57:54.608329", "modified": "2022-06-15 12:58:38.626595", "modified_by": "accounting@alyf.de", "parent": "PINV-0001", "parentfield": "taxes", "parenttype": "Purchase Invoice", "idx": 2, "docstatus": 1, "category": "Total", "add_deduct_tax": "Deduct", "charge_type": "On Net Total", "included_in_print_rate": 0, "included_in_paid_amount": 0, "account_head": "Payable VAT", "description": "Payable VAT", "rate": 19, "cost_center": "Main - ALYFG", "account_currency": "EUR", "tax_amount": 11.4, "tax_amount_after_discount_amount": 11.4, "total": 60, "base_tax_amount": 10.92, "base_total": 57.5, "base_tax_amount_after_discount_amount": 10.92, "item_wise_tax_detail": "{\"439\":[19.0,10.924129800000001]}", "doctype": "Purchase Taxes and Charges" } ], "advances": [], "advance_tax": [], "payment_schedule": [ { "name": "f95d1bce3e", "owner": "accounting@alyf.de", "creation": "2022-06-15 12:58:33.671781", "modified": "2022-06-15 12:58:38.626595", "modified_by": "accounting@alyf.de", "parent": "PINV-0001", "parentfield": "payment_schedule", "parenttype": "Purchase Invoice", "idx": 1, "docstatus": 1, "due_date": "2022-06-29", "invoice_portion": 100, "discount": 0, "payment_amount": 60, "outstanding": 60, "paid_amount": 0, "discounted_amount": 0, "base_payment_amount": 57.5, "doctype": "Payment Schedule" } ] } ```
General Ledger ![Bildschirmfoto 2022-06-29 um 18 51 57](https://user-images.githubusercontent.com/14891507/176492589-8b53830f-8bbe-4ca0-8bc5-341b2db774cf.png)
Olawale1 commented 2 years ago

We just encountered this today and have spent some time trying to figure out the issue. Thank God I searched the forums and found this reference! I absolutely agree with @barredterra and @rtdany10 that this should have been done in a major release (like V14) and should also be optional

Suprazz commented 2 years ago

This new update is really annoying. We've been using erpnext for many years and now after an update we need to search and figure out what is the problem because everything was working fine until now. You should clearly indicate the issue in the releases notes or on the forum because those kinds of problem are really annoying for non developer users that just want to use the software like it was.

nadarvinod commented 2 years ago

I am using ERPNext through API, so my frontend needs to change to accommodate this which would take time and i have already updated ERPNext to this version.

I have bypassed below functions in the production code to fix this issue temporarily. Will it impact anywhere else?

https://github.com/frappe/erpnext/blob/228f10bf30b0c9e304927b5a877cc0730a66ab7c/erpnext/controllers/accounts_controller.py#L177-L178

https://github.com/frappe/erpnext/blob/832a863d1e1af0a0def8a2305a4376abcc003962/erpnext/accounts/party.py#L391

ishanloya commented 2 years ago

We've been entering Purchase Invoices in foreign currencies for a while now. Accounting happens in our company currency only. The GL Entries and AP report show the correct value in our company currency.

Basically, we've been able to enter line items in invoice currency, while accounting in company currency only. ERPNext would convert the totals to company currency and create correct GL Entries. This is no longer possible now.

This is exactly the issue that we are facing now.

dj12djdjs commented 2 years ago

Closing as https://github.com/frappe/erpnext/pull/31572 is merged.

kingsleyuk2003 commented 2 years ago

image

yuntan0 commented 11 months ago

I am using ERPNext through API, so my frontend needs to change to accommodate this which would take time and i have already updated ERPNext to this version.

I have bypassed below functions in the production code to fix this issue temporarily. Will it impact anywhere else?

https://github.com/frappe/erpnext/blob/228f10bf30b0c9e304927b5a877cc0730a66ab7c/erpnext/controllers/accounts_controller.py#L177-L178

https://github.com/frappe/erpnext/blob/832a863d1e1af0a0def8a2305a4376abcc003962/erpnext/accounts/party.py#L391 Is it okkay to bypass party currency validation? I have the same issue. So I want to know the result of this bypass. Please let me know the result.

rtdany10 commented 11 months ago

@yuntan0 don't bypass, enable the allow multi-currency invoices against single party account in Accounts Settings

yuntan0 commented 10 months ago

@yuntan0 don't bypass, enable the allow multi-currency invoices against single party account in Accounts Settings

I have tried already.

But above validation logic block the foreign currency transaction.

Company Currency is CAD Supplier A default currency is USD. But sometimes we have to pay CAD.

I know we can create purchase invoice currency CAD but debit account can be USD. But accounting team said the CAD transaction should not be in currency evaluation.

So I changed debit currency to CAD. Then I can see this message ("Accounting Entry for {0}: {1} can only be made in currency: {2}").format(party_type, party, party_account_currency

Because th supplier already has USD transaction. But my client does not want to seperate the supplier.

Not only supplier but also customer.

Any Idea?

rtdany10 commented 10 months ago

An account can have only 1 base currency. From what I understood, you want to have multiple currency entries in the same account? I'm not very sure of how you are going to manage it.

Normally, if you do a CAD transaction against a USD account, system would calculate the USD value based on exchange rate and post ledger entries in USD only. You can't have both CAD and USD entries in a single account.


If you enable allow multi-currency invoices against single party account in Accounts Settings, all you have to do is select the currency in invoice and change nothing else.

yuntan0 commented 10 months ago

From what I understood, you want to have multiple currency entries in the same account? I'm not very sure of how you are going to manage it.

Yes I know. So in erpnext we can change debit to account or credit to account. Only one chart of account code use one currency. But it should not be belong to Customer and Supplier.

Like a below account code are different. But system does not allow multi currency in same customer.

Customer A (1100111 - Account Receivable - USD) / Sales 4100111 CAD Customer A (1100112 - Account Receivable - CAD) / Sales 4100111 CAD