diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/unverified/be_l10nbe_chart_template.json b/erpnext/accounts/doctype/account/chart_of_accounts/unverified/be_l10nbe_chart_template.json deleted file mode 100644 index 7fc58ce410b..00000000000 --- a/erpnext/accounts/doctype/account/chart_of_accounts/unverified/be_l10nbe_chart_template.json +++ /dev/null @@ -1,1539 +0,0 @@ -{ - "country_code": "be", - "name": "Belgian - PCMN", - "tree": { - "CLASSE 1": { - "BENEFICE (PERTE) REPORTE(E)": { - "B\u00e9n\u00e9fice report\u00e9": {}, - "Perte report\u00e9e": {} - }, - "CAPITAL": { - "Capital non appel\u00e9": {}, - "Capital souscrit ou capital personnel": { - "Capital amorti": {}, - "Capital non amorti": {} - }, - "Compte de l'exploitant": { - "Imp\u00f4ts personnels": {}, - "Op\u00e9rations courantes": {}, - "R\u00e9mun\u00e9rations et autres avantages": {} - } - }, - "COMPTES DE LIAISON DES ETABLISSEMENTS ET SUCCURSALES": {}, - "DETTES A PLUS D'UN AN": { - "Acomptes re\u00e7us sur commandes": {}, - "Autres emprunts": {}, - "Cautionnements re\u00e7us en num\u00e9raires": {}, - "Dettes commerciales": { - "Effets \u00e0 payer": { - "Entreprises apparent\u00e9es": { - "Entreprises avec lesquelles il existe un lien de participation": {}, - "Entreprises li\u00e9es": {} - }, - "Fournisseurs ordinaires": { - "Fournisseurs C.E.E.": {}, - "Fournisseurs belges": {}, - "Fournisseurs importation": {} - } - }, - "Fournisseurs : dettes en compte": { - "Entreprises apparent\u00e9es": { - "Entreprises avec lesquelles il existe un lien de participation": {}, - "Entreprises li\u00e9es": {} - }, - "Fournisseurs ordinaires": { - "Fournisseurs C.E.E.": {}, - "Fournisseurs belges": {}, - "Fournisseurs importation": {} - } - } - }, - "Dettes de location-financement et assimil\u00e9s": { - "Dettes de location-financement de biens immobiliers": {}, - "Dettes de location-financement de biens mobiliers": {}, - "Dettes sur droits r\u00e9els sur immeubles": {} - }, - "Dettes diverses": { - "Administrateurs, g\u00e9rants, associ\u00e9s": {}, - "Autres dettes diverses": {}, - "Autres entreprises avec lesquelles il existe un lien de participation": {}, - "Dettes envers les coparticipants des associations momentan\u00e9es et en participation": {}, - "Entreprises li\u00e9es": {}, - "Rentes viag\u00e8res capitalis\u00e9es": {} - }, - "Emprunts obligataires non subordonn\u00e9s": { - "Convertibles": {}, - "Non convertibles": {} - }, - "Emprunts subordonn\u00e9s": { - "Convertibles": {}, - "Non convertibles": {} - }, - "Etablissements de cr\u00e9dit": { - "Cr\u00e9dits d'acceptation": { - "Banque A": {}, - "Banque B": {} - }, - "Dettes en compte": { - "Banque A": {}, - "Banque B": {} - }, - "Promesses": { - "Banque A": {}, - "Banque B": {} - } - } - }, - "PLUS-VALUES DE REEVALUATION": { - "Plus-values de r\u00e9\u00e9valuation sur immobilisations corporelles": { - "Plus-values de r\u00e9\u00e9valuation": {}, - "Reprises de r\u00e9ductions de valeur": {} - }, - "Plus-values de r\u00e9\u00e9valuation sur immobilisations financi\u00e8res": { - "Plus-values de r\u00e9\u00e9valuation": {}, - "Reprises de r\u00e9ductions de valeur": {} - }, - "Plus-values de r\u00e9\u00e9valuation sur immobilisations incorporelles": { - "Plus-values de r\u00e9\u00e9valuation": {}, - "Reprises de r\u00e9ductions de valeur": {} - }, - "Plus-values de r\u00e9\u00e9valuation sur stocks": {}, - "Reprises de r\u00e9ductions de valeur sur placements de tr\u00e9sorerie": {} - }, - "PRIMES D'EMISSION": {}, - "PROVISIONS POUR RISQUES ET CHARGES": { - "Provisions pour autres risques et charges": {}, - "Provisions pour charges fiscales": {}, - "Provisions pour engagements relatifs \u00e0 l'acquisition ou \u00e0 la cession d'immobilisations": {}, - "Provisions pour ex\u00e9cution de commandes pass\u00e9es ou re\u00e7ues": {}, - "Provisions pour garanties techniques attach\u00e9es aux ventes et prestations d\u00e9j\u00e0 effectu\u00e9es par l'entreprise": {}, - "Provisions pour grosses r\u00e9parations et gros entretiens": {}, - "Provisions pour pensions et obligations similaires": {}, - "Provisions pour positions et march\u00e9s \u00e0 terme en devises ou positions et march\u00e9s \u00e0 terme en marchandises": {}, - "Provisions pour s\u00fbret\u00e9s personnelles ou r\u00e9elles constitu\u00e9es \u00e0 l'appui de dettes et d'engagements de tiers": {} - }, - "RESERVES": { - "R\u00e9serve l\u00e9gale": {}, - "R\u00e9serves disponibles": { - "R\u00e9serve pour installations en faveur du personnel 1333 R\u00e9serves libres": {}, - "R\u00e9serve pour renouvellement des immobilisations": {}, - "R\u00e9serve pour r\u00e9gularisation de dividendes": {} - }, - "R\u00e9serves immunis\u00e9es": {}, - "R\u00e9serves indisponibles": { - "Autres r\u00e9serves indisponibles": {}, - "R\u00e9serve pour actions propres": {} - } - }, - "SUBSIDES EN CAPITAL": { - "Montants obtenus": {}, - "Montants transf\u00e9r\u00e9s aux r\u00e9sultats": {} - }, - "root_type": "" - }, - "CLASSE 2. FRAIS D'ETABLISSEMENT. ACTIFS IMMOBILISES ET CREANCES A PLUS D'UN AN": { - "AUTRES IMMOBILISATIONS CORPORELLES": { - "Amortissements sur autres immobilisations corporelles": { - "Amortissements sur emballages r\u00e9cup\u00e9rables": {}, - "Amortissements sur frais d'am\u00e9nagement des locaux pris en location": {}, - "Amortissements sur maison d'habitation": {}, - "Amortissements sur mat\u00e9riel d'emballage": {}, - "Amortissements sur r\u00e9serve immobili\u00e8re": {} - }, - "Emballages r\u00e9cup\u00e9rables": {}, - "Frais d'am\u00e9nagements de locaux pris en location": {}, - "Maison d'habitation": {}, - "Mat\u00e9riel d'emballage": {}, - "Plus-values act\u00e9es sur autres immobilisations corporelles": {}, - "R\u00e9serve immobili\u00e8re": {} - }, - "CREANCES A PLUS D'UN AN": { - "Autres cr\u00e9ances": { - "Cr\u00e9ances douteuses": {}, - "Cr\u00e9ances en compte": { - "Cr\u00e9ances autres d\u00e9biteurs": {}, - "Cr\u00e9ances entreprises avec lesquelles il existe un lien de participation": {}, - "Cr\u00e9ances entreprises li\u00e9es": {} - }, - "Cr\u00e9ances r\u00e9sultant de la cession d'immobilisations donn\u00e9es en leasing": {}, - "Effets \u00e0 recevoir": { - "Sur autres d\u00e9biteurs": {}, - "Sur entreprises avec lesquelles il existe un lien de participation": {}, - "Sur entreprises li\u00e9es": {} - }, - "R\u00e9ductions de valeur act\u00e9es": {} - }, - "Cr\u00e9ances commerciales": { - "Acomptes vers\u00e9s": {}, - "Clients": { - "Cr\u00e9ances en compte sur entreprises li\u00e9es": {}, - "Cr\u00e9ances sur les coparticipants": {}, - "Sur clients Belgique": {}, - "Sur clients C.E.E.": {}, - "Sur clients exportation hors C.E.E.": {}, - "Sur entreprises avec lesquelles il existe un lien de participation": {} - }, - "Cr\u00e9ances douteuses": {}, - "Effets \u00e0 recevoir": { - "Sur clients Belgique": {}, - "Sur clients C.E.E.": {}, - "Sur clients exportation hors C.E.E.": {}, - "Sur entreprises avec lesquelles il existe un lien de participation": {}, - "Sur entreprises li\u00e9es": {} - }, - "Retenues sur garanties": {}, - "R\u00e9ductions de valeur act\u00e9es": {} - } - }, - "FRAIS D'ETABLISSEMENT": { - "Autres frais d'\u00e9tablissement": { - "Amortissements sur autres frais d'\u00e9tablissement": {}, - "Autres frais d'\u00e9tablissement": {} - }, - "Frais d'\u00e9mission d'emprunts et primes de remboursement": { - "Agios sur emprunts et frais d'\u00e9mission d'emprunts": {}, - "Amortissements sur agios sur emprunts et frais d'\u00e9mission d'emprunts": {} - }, - "Frais de constitution et d'augmentation de capital": { - "Amortissements sur frais de constitution et d'augmentation de capital": {}, - "Frais de constitution et d'augmentation de capital": {} - }, - "Frais de restructuration": { - "Amortissements sur frais de restructuration": {}, - "Co\u00fbt des frais de restructuration": {} - }, - "Int\u00e9r\u00eats intercalaires": { - "Amortissements sur int\u00e9r\u00eats intercalaires": {}, - "Int\u00e9r\u00eats intercalaires": {} - } - }, - "IMMOBILISATION DETENUES EN LOCATION-FINANCEMENT ET DROITS SIMILAIRES": { - "Installations, machines et outillage": { - "Amortissements sur installations, machines et outillage pris en leasing": {}, - "Installations": {}, - "Machines": {}, - "Outillage": {}, - "Plus-values act\u00e9es sur installations, machines et outillage pris en leasing": {} - }, - "Mobilier et mat\u00e9riel roulant": { - "Amortissements sur mobilier et mat\u00e9riel roulant en leasing": {}, - "Mat\u00e9riel roulant": {}, - "Mobilier": {}, - "Plus-values act\u00e9es sur mobilier et mat\u00e9riel roulant en leasing": {} - }, - "Terrains et constructions": { - "Amortissements et r\u00e9ductions de valeur sur terrains et constructions en leasing": {}, - "Constructions": {}, - "Plus-values sur emphyt\u00e9ose, leasing et droits similaires : terrains et constructions": {}, - "Terrains": {} - } - }, - "IMMOBILISATIONS CORPORELLES EN COURS ET ACOMPTES VERSES": { - "Avances et acomptes vers\u00e9s sur immobilisations en cours": {}, - "Immobilisations en cours": { - "Autres immobilisations corporelles": {}, - "Constructions": {}, - "Installations, machines et outillage": {}, - "Mobilier et mat\u00e9riel roulant": {} - } - }, - "IMMOBILISATIONS FINANCIERES": { - "Autres actions et parts": { - "Montants non appel\u00e9s": {}, - "Plus-values act\u00e9es": {}, - "R\u00e9ductions de valeur act\u00e9es": {}, - "Valeur d'acquisition": {} - }, - "Autres cr\u00e9ances": { - "Cr\u00e9ances douteuses": {}, - "Cr\u00e9ances en compte": {}, - "Effets \u00e0 recevoir": {}, - "R\u00e9ductions de valeur act\u00e9es": {}, - "Titres \u00e0 revenu fixe": {} - }, - "Cautionnements vers\u00e9s en num\u00e9raires": { - "Autres cautionnements vers\u00e9s en num\u00e9raires": {}, - "Eau": {}, - "Electricit\u00e9": {}, - "Gaz": {}, - "T\u00e9l\u00e9phone, t\u00e9lefax, t\u00e9lex": {} - }, - "Cr\u00e9ances sur des entreprises avec lesquelles il existe un lien de participation": { - "Cr\u00e9ances douteuses": {}, - "Cr\u00e9ances en compte": {}, - "Effets \u00e0 recevoir": {}, - "R\u00e9ductions de valeurs act\u00e9es": {}, - "Titres \u00e0 revenu fixe": {} - }, - "Cr\u00e9ances sur des entreprises li\u00e9es": { - "Cr\u00e9ances douteuses": {}, - "Cr\u00e9ances en compte": {}, - "Effets \u00e0 recevoir": {}, - "R\u00e9ductions de valeurs act\u00e9es": {}, - "Titres \u00e0 revenu fixes": {} - }, - "Participations dans des entreprises avec lesquelles il existe un lien de participation": { - "Montants non appel\u00e9s": {}, - "Plus-values act\u00e9es": {}, - "R\u00e9ductions de valeurs act\u00e9es": {}, - "Valeur d'acquisition": {} - }, - "Participations dans des entreprises li\u00e9es": { - "Montants non appel\u00e9s": {}, - "Plus-values act\u00e9es": {}, - "R\u00e9ductions de valeurs act\u00e9es": {}, - "Valeur d'acquisition": {} - } - }, - "IMMOBILISATIONS INCORPORELLES": { - "Acomptes vers\u00e9s": {}, - "Concessions, brevets, licences, savoir-faire, marques et droits similaires": { - "Amortissements sur concessions, brevets, etc...": {}, - "Concessions, brevets, licences, savoir-faire, marques, etc...": {}, - "Plus-values act\u00e9es sur concessions, brevets, etc...": {} - }, - "Frais de recherche et de d\u00e9veloppement": { - "Amortissements sur frais de recherche et de mise au point": {}, - "Frais de recherche et de mise au point": {}, - "Plus-values act\u00e9es sur frais de recherche et de mise au point": {} - }, - "Goodwill": { - "Amortissements sur goodwill": {}, - "Co\u00fbt d'acquisition": {}, - "Plus-values act\u00e9es": {} - } - }, - "INSTALLATIONS, MACHINES ET OUTILLAGE": { - "Amortissements": { - "Sur installations": {}, - "Sur machines": {}, - "Sur outillage": {} - }, - "Installations": { - "Installation d'eau": {}, - "Installation d'\u00e9lectricit\u00e9": {}, - "Installation de chargement": {}, - "Installation de chauffage": {}, - "Installation de conditionnement d'air": {}, - "Installation de gaz": {}, - "Installation de vapeur": {} - }, - "Machines": { - "Division A": {}, - "Division B": {} - }, - "Outillage": { - "Division A": {}, - "Division B": {} - }, - "Plus-values act\u00e9es": { - "Sur installations": {}, - "Sur machines": {}, - "Sur outillage": {} - } - }, - "MOBILIER ET MATERIEL ROULANT": { - "Mat\u00e9riel roulant": { - "Amortissements sur mat\u00e9riel roulant": { - "Amortissements sur mat\u00e9riel automobile": {}, - "Idem sur mat\u00e9riel a\u00e9rien": {}, - "Idem sur mat\u00e9riel ferroviaire": {}, - "Idem sur mat\u00e9riel fluvial": {}, - "Idem sur mat\u00e9riel naval": {} - }, - "Mat\u00e9riel automobile": { - "Camions": {}, - "Voitures": {} - }, - "Mat\u00e9riel a\u00e9rien": {}, - "Mat\u00e9riel ferroviaire": {}, - "Mat\u00e9riel fluvial": {}, - "Mat\u00e9riel naval": {}, - "Plus-values sur mat\u00e9riel roulant": { - "Idem sur mat\u00e9riel a\u00e9rien": {}, - "Idem sur mat\u00e9riel ferroviaire": {}, - "Idem sur mat\u00e9riel fluvial": {}, - "Idem sur mat\u00e9riel naval": {}, - "Plus-values sur mat\u00e9riel automobile": {} - } - }, - "Mobilier": { - "Amortissements": { - "Amortissements sur mat\u00e9riel de bureau et service social": {}, - "Amortissements sur mobilier": {} - }, - "Mat\u00e9riel de bureau et de service social": { - "Des autres b\u00e2timents d'exploitation": {}, - "Des b\u00e2timents administratifs et commerciaux": {}, - "Des b\u00e2timents industriels": {}, - "Des oeuvres sociales": {} - }, - "Mobilier": { - "Mobilier des autres b\u00e2timents d'exploitation": {}, - "Mobilier des b\u00e2timents administratifs et commerciaux": {}, - "Mobilier des b\u00e2timents industriels": {}, - "Mobilier oeuvres sociales": {} - }, - "Plus-values act\u00e9es": { - "Plus-values act\u00e9es sur mat\u00e9riel de bureau et service social": {}, - "Plus-values act\u00e9es sur mobilier": {} - } - } - }, - "TERRAINS ET CONSTRUCTIONS": { - "Autres droits r\u00e9els sur des immeubles": { - "Amortissements": {}, - "Plus-values act\u00e9es": {}, - "Valeur d'acquisition": {} - }, - "Constructions": { - "Amortissements sur constructions": { - "Sur autres b\u00e2timents d'exploitation": {}, - "Sur b\u00e2timents administratifs et commerciaux": {}, - "Sur b\u00e2timents industriels": {}, - "Sur constructions sur sol d'autrui": {}, - "Sur frais d'acquisition sur constructions": {}, - "Sur voies de transport et ouvrages d'art": {} - }, - "Autres b\u00e2timents d'exploitation": {}, - "B\u00e2timents administratifs et commerciaux": {}, - "B\u00e2timents industriels": {}, - "Constructions sur sol d'autrui": {}, - "Frais d'acquisition sur constructions": {}, - "Plus-values act\u00e9es": { - "Sur autres b\u00e2timents d'exploitation": {}, - "Sur b\u00e2timents administratifs et commerciaux": {}, - "Sur b\u00e2timents industriels": {}, - "Sur voies de transport et ouvrages d'art": {} - }, - "Voies de transport et ouvrages d'art": {} - }, - "Terrains": { - "Amortissements et r\u00e9ductions de valeur": { - "Amortissements sur frais d'acquisition": {}, - "R\u00e9ductions de valeur sur terrains": {} - }, - "Frais d'acquisition sur terrains": {}, - "Plus-values act\u00e9es sur terrains": {}, - "Terrains": {} - }, - "Terrains b\u00e2tis": { - "Amortissements sur terrains b\u00e2tis": { - "Sur autres b\u00e2timents d'exploitation": {}, - "Sur b\u00e2timents administratifs et commerciaux": {}, - "Sur b\u00e2timents industriels": {}, - "Sur frais d'acquisition des terrains b\u00e2tis": {}, - "Sur voies de transport et ouvrages d'art": {} - }, - "Plus-values act\u00e9es": { - "Sur autres b\u00e2timents d'exploitation": {}, - "Sur b\u00e2timents administratifs et commerciaux": {}, - "Sur b\u00e2timents industriels": {}, - "Sur voies de transport et ouvrages d'art": {} - }, - "Valeur d'acquisition": { - "Autres b\u00e2timents d'exploitation": {}, - "B\u00e2timents administratifs et commerciaux": {}, - "B\u00e2timents industriels": {}, - "Frais d'acquisition des terrains \u00e0 b\u00e2tir": {}, - "Voies de transport et ouvrages d'art": {} - } - } - }, - "root_type": "" - }, - "CLASSE 3. STOCK ET COMMANDES EN COURS D'EXECUTION": { - "ACOMPTES VERSES SUR ACHATS POUR STOCKS": { - "Acomptes vers\u00e9s": { - "account_type": "Stock" - }, - "R\u00e9ductions de valeur act\u00e9es": { - "account_type": "Stock" - }, - "account_type": "Stock" - }, - "APPROVISIONNEMENTS - MATIERES PREMIERES": { - "R\u00e9ductions de valeur act\u00e9es": { - "account_type": "Stock" - }, - "Valeur d'acquisition": { - "account_type": "Stock" - }, - "account_type": "Stock" - }, - "APPROVISIONNEMENTS ET FOURNITURES": { - "R\u00e9ductions de valeur act\u00e9es": { - "account_type": "Stock" - }, - "Valeur d'acquisition": { - "Emballages commerciaux": { - "Emballages perdus": { - "account_type": "Stock" - }, - "Emballages r\u00e9cup\u00e9rables": { - "account_type": "Stock" - }, - "account_type": "Stock" - }, - "Energie, charbon, coke, Mazout, essence, propane": { - "account_type": "Stock" - }, - "Fournitures de services sociaux": { - "account_type": "Stock" - }, - "Fournitures diverses et petit outillage": { - "account_type": "Stock" - }, - "Imprim\u00e9s et fournitures de bureau": { - "account_type": "Stock" - }, - "Mati\u00e8res d'approvisionnement": { - "account_type": "Stock" - }, - "Produits d'entretien": { - "account_type": "Stock" - }, - "account_type": "Stock" - }, - "account_type": "Stock" - }, - "COMMANDES EN COURS D'EXECUTION": { - "B\u00e9n\u00e9fice pris en compte": { - "account_type": "Stock" - }, - "R\u00e9ductions de valeur act\u00e9es": { - "account_type": "Stock" - }, - "Valeur d'acquisition": { - "account_type": "Stock" - }, - "account_type": "Stock" - }, - "EN COURS DE FABRICATION": { - "R\u00e9ductions de valeur act\u00e9es": { - "account_type": "Stock" - }, - "Valeur d'acquisition": { - "D\u00e9chets": { - "account_type": "Stock" - }, - "Produits en cours de fabrication": { - "account_type": "Stock" - }, - "Produits semi-ouvr\u00e9s": { - "account_type": "Stock" - }, - "Rebuts": { - "account_type": "Stock" - }, - "Travaux en association momentan\u00e9e": { - "account_type": "Stock" - }, - "Travaux en cours": { - "account_type": "Stock" - }, - "account_type": "Stock" - }, - "account_type": "Stock" - }, - "IMMEUBLES DESTINES A LA VENTE": { - "Immeubles construits en vue de leur revente": { - "Immeuble A": { - "account_type": "Stock" - }, - "Immeuble B": { - "account_type": "Stock" - }, - "account_type": "Stock" - }, - "R\u00e9ductions de valeurs act\u00e9es": { - "account_type": "Stock" - }, - "Valeur d'acquisition": { - "Immeuble A": { - "account_type": "Stock" - }, - "Immeuble B": { - "account_type": "Stock" - }, - "account_type": "Stock" - }, - "account_type": "Stock" - }, - "MARCHANDISES": { - "R\u00e9ductions de valeur act\u00e9es": { - "account_type": "Stock" - }, - "Valeur d'acquisition": { - "Groupe A": { - "account_type": "Stock" - }, - "Groupe B": { - "account_type": "Stock" - }, - "account_type": "Stock" - }, - "account_type": "Stock" - }, - "PRODUITS FINIS": { - "R\u00e9ductions de valeur act\u00e9es": { - "account_type": "Stock" - }, - "Valeur d'acquisition": { - "Produits finis": { - "account_type": "Stock" - }, - "account_type": "Stock" - }, - "account_type": "Stock" - }, - "account_type": "Stock", - "root_type": "" - }, - "CLASSE 4. CREANCES ET DETTES A UN AN AU PLUS": { - "ACOMPTES RECUS SUR COMMANDES": { - "account_type": "Payable" - }, - "AUTRES CREANCES": { - "Capital appel\u00e9, non vers\u00e9": { - "Actionnaires d\u00e9faillants": { - "account_type": "Receivable" - }, - "Appels de fonds": { - "account_type": "Receivable" - } - }, - "Cautionnements vers\u00e9s en num\u00e9raires": { - "account_type": "Receivable" - }, - "Cr\u00e9ances diverses": { - "Associ\u00e9s": { - "account_type": "Receivable" - }, - "Avances et pr\u00eats au personnel": { - "account_type": "Receivable" - }, - "Compte courant des administrateurs et g\u00e9rants": { - "account_type": "Receivable" - }, - "Compte courant des associ\u00e9s en S.P.R.L.": { - "account_type": "Receivable" - }, - "Cr\u00e9ances sur soci\u00e9t\u00e9s apparent\u00e9es": { - "account_type": "Receivable" - }, - "Emballages et mat\u00e9riel \u00e0 rendre": { - "account_type": "Receivable" - }, - "Etat et \u00e9tablissements publics": { - "Autres cr\u00e9ances": { - "account_type": "Receivable" - }, - "Subsides \u00e0 recevoir": { - "account_type": "Receivable" - } - }, - "Rabais, ristournes, remises \u00e0 obtenir et autres avoirs non encore re\u00e7us": { - "account_type": "Receivable" - } - }, - "Cr\u00e9ances douteuses": { - "account_type": "Receivable" - }, - "Imp\u00f4ts et versements fiscaux \u00e0 r\u00e9cup\u00e9rer": { - "Imp\u00f4ts \u00e9trangers": { - "account_type": "Receivable" - }, - "\u00e0 4124 Imp\u00f4ts belges sur le r\u00e9sultat": { - "account_type": "Receivable" - }, - "\u00e0 4127 Autres imp\u00f4ts belges": { - "account_type": "Receivable" - } - }, - "Produits \u00e0 recevoir": { - "account_type": "Receivable" - }, - "R\u00e9ductions de valeur act\u00e9es": { - "account_type": "Receivable" - }, - "T.V.A. \u00e0 r\u00e9cup\u00e9rer": { - "Compte courant administration T.V.A.": { - "account_type": "Receivable" - }, - "T.V.A D\u00e9ductible": { - "account_type": "Receivable" - }, - "Taxe d'\u00e9galisation due": { - "account_type": "Receivable" - } - } - }, - "COMPTES DE REGULARISATION ET COMPTES D'ATTENTE": { - "Charges \u00e0 imputer": { - "account_type": "Payable" - }, - "Charges \u00e0 reporter": { - "account_type": "Payable" - }, - "Comptes d'attente": { - "Compte d'attente": { - "account_type": "Payable" - }, - "Compte de r\u00e9partition p\u00e9riodique des charges": { - "account_type": "Payable" - }, - "Transferts d'exercice": { - "account_type": "Payable" - } - }, - "Produits acquis": { - "Produits d'exploitation": { - "Autres produits d'exploitation": { - "account_type": "Payable" - }, - "Commissions \u00e0 obtenir": { - "account_type": "Payable" - }, - "Ristournes, rabais \u00e0 obtenir": { - "account_type": "Payable" - } - }, - "Produits financiers": { - "Autres produits financiers": { - "account_type": "Payable" - }, - "Int\u00e9r\u00eats courus et non \u00e9chus sur pr\u00eats et d\u00e9bits": { - "account_type": "Payable" - } - } - }, - "Produits \u00e0 reporter": { - "Produits d'exploitation \u00e0 reporter": { - "account_type": "Payable" - }, - "Produits financiers \u00e0 reporter": { - "account_type": "Payable" - } - } - }, - "CREANCES COMMERCIALES": { - "Acomptes vers\u00e9s": { - "account_type": "Receivable" - }, - "Clients": { - "Clients": { - "account_type": "Receivable" - }, - "Cr\u00e9ances r\u00e9sultant de livraisons de biens": { - "account_type": "Receivable" - }, - "Rabais, remises, ristournes \u00e0 accorder et autres notes de cr\u00e9dit \u00e0 \u00e9tablir": { - "account_type": "Receivable" - } - }, - "Clients : retenues sur garanties": { - "account_type": "Receivable" - }, - "Clients, cr\u00e9ances courantes, entreprises apparent\u00e9es, administrateurs et g\u00e9rants": { - "Administrateurs et g\u00e9rants d'entreprise": { - "account_type": "Receivable" - }, - "Autres entreprises avec lesquelles il existe un lien de participation": { - "account_type": "Receivable" - }, - "Entreprises li\u00e9es": { - "account_type": "Receivable" - } - }, - "Compensation clients": { - "account_type": "Receivable" - }, - "Cr\u00e9ances douteuses": { - "account_type": "Receivable" - }, - "Effets \u00e0 recevoir": { - "Effets \u00e0 l'encaissement": { - "account_type": "Receivable" - }, - "Effets \u00e0 l'escompte": { - "account_type": "Receivable" - }, - "Effets \u00e0 recevoir": { - "account_type": "Receivable" - } - }, - "Effets \u00e0 recevoir sur entreprises apparent\u00e9es et administrateurs et g\u00e9rants": { - "Administrateurs et g\u00e9rants de l'entreprise": { - "account_type": "Receivable" - }, - "Autres entreprises avec lesquelles il existe un lien de participation": { - "account_type": "Receivable" - }, - "Entreprises li\u00e9es": { - "account_type": "Receivable" - } - }, - "Produits \u00e0 recevoir": { - "account_type": "Receivable" - }, - "R\u00e9ductions de valeur act\u00e9es": { - "account_type": "Receivable" - } - }, - "DETTES A PLUS D'UN AN ECHEANT DANS L'ANNEE": { - "Autres emprunts": { - "account_type": "Payable" - }, - "Cautionnements re\u00e7us en num\u00e9raires": { - "account_type": "Payable" - }, - "Dettes commerciales": { - "Effets \u00e0 payer": { - "account_type": "Payable" - }, - "Fournisseurs": { - "account_type": "Payable" - } - }, - "Dettes de location-financement et assimil\u00e9es": { - "Financement de biens immobiliers": { - "account_type": "Payable" - }, - "Financement de biens mobiliers": { - "account_type": "Payable" - } - }, - "Dettes diverses": { - "Administrateurs, g\u00e9rants, associ\u00e9s": { - "account_type": "Payable" - }, - "Autres dettes": { - "account_type": "Payable" - }, - "Entreprises avec lesquelles il existe un lien de participation": { - "account_type": "Payable" - }, - "Entreprises li\u00e9es": { - "account_type": "Payable" - } - }, - "Emprunts obligataires non subordonn\u00e9s": { - "Convertibles": { - "account_type": "Payable" - }, - "Non convertibles": { - "account_type": "Payable" - } - }, - "Emprunts subordonn\u00e9s": { - "Convertibles": { - "account_type": "Payable" - }, - "Non convertibles": { - "account_type": "Payable" - } - }, - "Etablissements de cr\u00e9dit": { - "Cr\u00e9dits d'acceptation": { - "account_type": "Payable" - }, - "Dettes en compte": { - "account_type": "Payable" - }, - "Promesses": { - "account_type": "Payable" - } - } - }, - "DETTES COMMERCIALES": { - "Acomptes re\u00e7us": { - "account_type": "Payable" - }, - "Compensations fournisseurs": { - "account_type": "Payable" - }, - "Effets \u00e0 payer": { - "Entreprises apparent\u00e9es": { - "Entreprises avec lesquelles il existe un lien de participation": { - "account_type": "Payable" - }, - "Entreprises li\u00e9es": { - "account_type": "Payable" - } - }, - "Fournisseurs ordinaires": { - "Fournisseurs CEE": { - "account_type": "Payable" - }, - "Fournisseurs belges": { - "account_type": "Payable" - }, - "Fournisseurs importation": { - "account_type": "Payable" - } - } - }, - "Factures \u00e0 recevoir": { - "account_type": "Payable" - }, - "Fournisseurs": { - "Dettes envers les coparticipants": { - "account_type": "Payable" - }, - "Entreprises apparent\u00e9es": { - "Entreprises avec lesquelles il existe un lien de participation": { - "account_type": "Payable" - }, - "Entreprises li\u00e9es": { - "account_type": "Payable" - } - }, - "Fournisseurs - retenues de garanties": { - "account_type": "Payable" - }, - "Fournisseurs ordinaires": { - "Fournisseurs CEE": { - "account_type": "Payable" - }, - "Fournisseurs belges": { - "account_type": "Payable" - }, - "Fournisseurs importation": { - "account_type": "Payable" - } - } - } - }, - "DETTES DECOULANT DE L'AFFECTATION DES RESULTATS": { - "Autres allocataires": { - "account_type": "Payable" - }, - "Dividendes de l'exercice": { - "account_type": "Payable" - }, - "Dividendes et tanti\u00e8mes d'exercices ant\u00e9rieurs": { - "account_type": "Payable" - }, - "Tanti\u00e8mes de l'exercice": { - "account_type": "Payable" - } - }, - "DETTES DIVERSES": { - "Acomptes re\u00e7us d'autres tiers \u00e0 moins d'un an": { - "account_type": "Payable" - }, - "Actionnaires - capital \u00e0 rembourser": { - "account_type": "Payable" - }, - "Autres dettes diverses": { - "account_type": "Payable" - }, - "Cautionnements re\u00e7us en num\u00e9raires": { - "account_type": "Payable" - }, - "Emballages et mat\u00e9riel consign\u00e9s": { - "account_type": "Payable" - }, - "Obligations et coupons \u00e9chus": { - "account_type": "Payable" - }, - "Participation du personnel \u00e0 payer": { - "account_type": "Payable" - } - }, - "DETTES FINANCIERES": { - "Autres emprunts": { - "account_type": "Payable" - }, - "Etablissements de cr\u00e9dit. Cr\u00e9dits d'acceptation": { - "account_type": "Payable" - }, - "Etablissements de cr\u00e9dit. Dettes en compte courant": { - "account_type": "Payable" - }, - "Etablissements de cr\u00e9dit. Emprunts en compte \u00e0 terme fixe": { - "account_type": "Payable" - }, - "Etablissements de cr\u00e9dit. Promesses": { - "account_type": "Payable" - } - }, - "DETTES FISCALES, SALARIALES ET SOCIALES": { - "Autres dettes sociales": { - "Assurances relatives au personnel": { - "Assurance groupe ": { - "account_type": "Payable" - }, - "Assurance loi": { - "account_type": "Payable" - }, - "Assurance salaire garanti ": { - "account_type": "Payable" - }, - "Assurances individuelles": { - "account_type": "Payable" - } - }, - "Caisse d'assurances sociales pour travailleurs ind\u00e9pendants": { - "account_type": "Payable" - }, - "Dettes et provisions sociales diverses": { - "account_type": "Payable" - }, - "D\u00e9parts de personnel": { - "account_type": "Payable" - }, - "Oppositions sur r\u00e9mun\u00e9rations": { - "account_type": "Payable" - }, - "Provision pour gratifications de fin d'ann\u00e9e": { - "account_type": "Payable" - } - }, - "Dettes fiscales estim\u00e9es": { - "Imp\u00f4ts \u00e0 l'\u00e9tranger": { - "account_type": "Payable" - }, - "\u00e0 4504 Imp\u00f4ts sur le r\u00e9sultat": { - "account_type": "Payable" - }, - "\u00e0 4507 Autres imp\u00f4ts en Belgique": { - "account_type": "Payable" - } - }, - "Imp\u00f4ts et taxes \u00e0 payer": { - "Autres imp\u00f4ts et taxes en Belgique": { - "Autres imp\u00f4ts et taxes \u00e0 payer": { - "account_type": "Payable" - }, - "Imp\u00f4ts communaux \u00e0 payer": { - "account_type": "Payable" - }, - "Imp\u00f4ts provinciaux \u00e0 payer": { - "account_type": "Payable" - }, - "Pr\u00e9compte immobilier": { - "account_type": "Payable" - } - }, - "Autres imp\u00f4ts sur le r\u00e9sultat": { - "account_type": "Payable" - }, - "Imp\u00f4ts et taxes \u00e0 l'\u00e9tranger": { - "account_type": "Payable" - } - }, - "Office National de la S\u00e9curit\u00e9 Sociale": { - "1er trimestre": { - "account_type": "Payable" - }, - "2\u00e8me trimestre": { - "account_type": "Payable" - }, - "3\u00e8me trimestre": { - "account_type": "Payable" - }, - "4\u00e8me trimestre": { - "account_type": "Payable" - }, - "Arri\u00e9r\u00e9s": { - "account_type": "Payable" - } - }, - "Pr\u00e9comptes retenus": { - "Autres pr\u00e9comptes retenus": { - "account_type": "Payable" - }, - "Pr\u00e9compte mobilier retenu sur dividendes attribu\u00e9s": { - "account_type": "Payable" - }, - "Pr\u00e9compte mobilier retenu sur int\u00e9r\u00eats pay\u00e9s": { - "account_type": "Payable" - }, - "Pr\u00e9compte professionnel retenu sur r\u00e9mun\u00e9rations": { - "account_type": "Payable" - }, - "Pr\u00e9compte professionnel retenu sur tanti\u00e8mes": { - "account_type": "Payable" - } - }, - "P\u00e9cules de vacances": { - "Direction": { - "account_type": "Payable" - }, - "Employ\u00e9s": { - "account_type": "Payable" - }, - "Ouvriers": { - "account_type": "Payable" - } - }, - "R\u00e9mun\u00e9rations": { - "Administrateurs, g\u00e9rants et commissaires": { - "account_type": "Payable" - }, - "Direction": { - "account_type": "Payable" - }, - "Employ\u00e9s": { - "account_type": "Payable" - }, - "Ouvriers": { - "account_type": "Payable" - } - }, - "T.V.A. \u00e0 payer": { - "Compte courant administration T.V.A.": { - "account_type": "Payable" - }, - "T.V.A. \u00e0 payer": { - "account_type": "Payable" - }, - "T.V.A. \u00e0 payer - Cocontractant": { - "account_type": "Receivable" - }, - "T.V.A. \u00e0 payer - Import": { - "account_type": "Receivable" - }, - "T.V.A. \u00e0 payer - Intra-communautaire": { - "account_type": "Receivable" - }, - "Taxe d'\u00e9galisation due": { - "account_type": "Payable" - } - } - }, - "root_type": "" - }, - "CLASSE 5. PLACEMENTS DE TRESORERIE ET DE VALEURS DISPONIBLES": { - "ACTIONS ET PARTS": { - "Montants non appel\u00e9s": { - "account_type": "Cash" - }, - "R\u00e9ductions de valeur act\u00e9es": { - "account_type": "Cash" - }, - "Valeur d'acquisition": { - "account_type": "Cash" - } - }, - "ACTIONS PROPRES": { - "account_type": "Cash" - }, - "CAISSES": { - "Caisses - esp\u00e8ces": { - "Caisse principale": { - "account_type": "Cash" - } - }, - "Caisses - timbres": { - "account_type": "Cash" - } - }, - "DEPOTS A TERME": { - "D'un mois au plus": { - "account_type": "Cash" - }, - "De plus d'un an": { - "account_type": "Cash" - }, - "De plus d'un mois et \u00e0 un an au plus": { - "account_type": "Cash" - }, - "R\u00e9ductions de valeur act\u00e9es": { - "account_type": "Cash" - } - }, - "ETABLISSEMENTS DE CREDIT.": { - "Comptes ouverts aupr\u00e8s des divers \u00e9tablissements": {} - }, - "OFFICE DES CHEQUES POSTAUX": { - "Ch\u00e8ques \u00e9mis": { - "account_type": "Cash" - }, - "Compte courant": { - "account_type": "Cash" - } - }, - "TITRES A REVENUS FIXES": { - "R\u00e9ductions de valeur act\u00e9es": { - "account_type": "Cash" - }, - "Valeur d'acquisition": { - "account_type": "Cash" - } - }, - "VALEURS ECHUES A L'ENCAISSEMENT": { - "Ch\u00e8ques \u00e0 encaisser": { - "account_type": "Cash" - }, - "Coupons \u00e0 encaisser": { - "account_type": "Cash" - } - }, - "VIREMENTS INTERNES": { - "account_type": "Cash" - }, - "root_type": "" - }, - "CLASSE 6. - CHARGES": { - "AFFECTATION DES RESULTATS": { - "Administrateurs ou g\u00e9rants": {}, - "Autres allocataires": {}, - "B\u00e9n\u00e9fice \u00e0 reporter": {}, - "Dotation aux autres r\u00e9serves": {}, - "Dotation \u00e0 la r\u00e9serve l\u00e9gale": {}, - "Perte report\u00e9e de l'exercice pr\u00e9c\u00e9dent": {}, - "R\u00e9mun\u00e9ration du capital": {} - }, - "AMORTISSEMENTS, REDUCTIONS DE VALEUR ET PROVISIONS POUR RISQUES ET CHARGES": { - "Dotations aux amortissements et aux r\u00e9ductions de valeur sur immobilisations": { - "Dotations aux amortissements sur frais d'\u00e9tablissement": {}, - "Dotations aux amortissements sur immobilisations corporelles": {}, - "Dotations aux amortissements sur immobilisations incorporelles": {}, - "Dotations aux r\u00e9ductions de valeur sur immobilisations corporelles": {}, - "Dotations aux r\u00e9ductions de valeur sur immobilisations incorporelles": {} - }, - "Provisions pour autres risques et charges": { - "Dotations ": {}, - "Utilisations et reprises": {} - }, - "Provisions pour grosses r\u00e9parations et gros entretiens": { - "Dotations": {}, - "Utilisations et reprises": {} - }, - "Provisions pour pensions et obligations similaires": { - "Dotations": {}, - "Utilisations et reprises": {} - }, - "R\u00e9ductions de valeur sur commandes en cours d'ex\u00e9cution": { - "Dotations": {}, - "Reprises": {} - }, - "R\u00e9ductions de valeur sur cr\u00e9ances commerciales \u00e0 plus d'un an": { - "Dotations": {}, - "Reprises": {} - }, - "R\u00e9ductions de valeur sur cr\u00e9ances commerciales \u00e0 un an au plus": { - "Dotations": {}, - "Reprises": {} - }, - "R\u00e9ductions de valeur sur stocks": { - "Dotations": {}, - "Reprises": {} - } - }, - "APPROVISIONNEMENTS ET MARCHANDISES": { - "Achats d'immeubles destin\u00e9s \u00e0 la revente": {}, - "Achats de fournitures": {}, - "Achats de marchandises": {}, - "Achats de mati\u00e8res premi\u00e8res": {}, - "Achats de services, travaux et \u00e9tudes": {}, - "Remises, ristournes et rabais obtenus sur achats": {}, - "Sous-traitances g\u00e9n\u00e9rales": {}, - "Variations de stocks": { - "D'immeubles destin\u00e9s \u00e0 la vente": {}, - "De fournitures": {}, - "De marchandises": {}, - "De mati\u00e8res premi\u00e8res": {} - } - }, - "AUTRES CHARGES D'EXPLOITATION": { - "Charges d'exploitation port\u00e9es \u00e0 l'actif au titre de restructuration": {}, - "Charges fiscales d'exploitation": { - "Imp\u00f4ts provinciaux et communaux": { - "Taxe sur la force motrice": {}, - "Taxe sur le personnel occup\u00e9": {} - }, - "Taxes diverses": {}, - "Taxes et imp\u00f4ts directs": { - "Taxes sur autos et camions": {} - }, - "Taxes et imp\u00f4ts indirects": { - "Droits d'enregistrement": {}, - "T.V.A. non d\u00e9ductible": {}, - "Timbres fiscaux pris en charge par la firme": {} - } - }, - "Moins-values sur r\u00e9alisations courantes d'immobilisations corporelles": {}, - "Moins-values sur r\u00e9alisations de cr\u00e9ances commerciales": {}, - "\u00e0 648 Charges d'exploitations diverses": {} - }, - "CHARGES EXCEPTIONNELLES": { - "Amortissements et r\u00e9ductions de valeur exceptionnels": { - "Sur frais d'\u00e9tablissement": {}, - "Sur immobilisations corporelles": {}, - "Sur immobilisations incorporelles": {} - }, - "Autres charges exceptionnelles": {}, - "Charges exceptionnelles transf\u00e9r\u00e9es \u00e0 l'actif en frais de restructuration": {}, - "Diff\u00e9rence de charge": {}, - "Moins-values sur r\u00e9alisation d'actifs immobilis\u00e9s": { - "Sur immeubles acquis ou construits en vue de la revente": {}, - "Sur immobilisations corporelles": {}, - "Sur immobilisations d\u00e9tenues en location-financement et droits similaires": {}, - "Sur immobilisations financi\u00e8res": {}, - "Sur immobilisations incorporelles": {} - }, - "Provisions pour risques et charges exceptionnels": {}, - "P\u00e9nalit\u00e9s et amendes diverses": {}, - "R\u00e9ductions de valeur sur immobilisations financi\u00e8res": {} - }, - "CHARGES FINANCIERES": { - "Charges d'escompte de cr\u00e9ances": {}, - "Charges des dettes": { - "Amortissements des agios et frais d'\u00e9mission d'emprunts": {}, - "Autres charges de dettes": {}, - "Int\u00e9r\u00eats intercalaires port\u00e9s \u00e0 l'actif": {}, - "Int\u00e9r\u00eats, commissions et frais aff\u00e9rents aux dettes": {} - }, - "Commissions sur ouvertures de cr\u00e9dit, cautions, avals": {}, - "Diff\u00e9rences de change": {}, - "Ecarts de conversion des devises": {}, - "Frais de banques, de ch\u00e8ques postaux": {}, - "Frais de vente des titres": {}, - "Moins-values sur r\u00e9alisation d'actifs circulants": {}, - "R\u00e9ductions de valeur sur actifs circulants": { - "Dotations ": {}, - "Reprises": {} - } - }, - "IMPOTS SUR LE RESULTAT": { - "Imp\u00f4ts belges sur le r\u00e9sultat d'exercices ant\u00e9rieurs": { - "Provisions fiscales constitu\u00e9es": {}, - "Suppl\u00e9ments d'imp\u00f4ts dus ou vers\u00e9s": {}, - "Suppl\u00e9ments d'imp\u00f4ts estim\u00e9s": {} - }, - "Imp\u00f4ts belges sur le r\u00e9sultat de l'exercice": { - "Charges fiscales estim\u00e9es": {}, - "Exc\u00e9dent de versements d'imp\u00f4ts et pr\u00e9comptes port\u00e9 \u00e0 l'actif": {}, - "Imp\u00f4ts et pr\u00e9comptes dus ou vers\u00e9s": {} - }, - "Imp\u00f4ts \u00e9trangers sur le r\u00e9sultat d'exercices ant\u00e9rieurs": {}, - "Imp\u00f4ts \u00e9trangers sur le r\u00e9sultat de l'exercice": {} - }, - "REMUNERATIONS, CHARGES SOCIALES ET PENSIONS": { - "Autres frais de personnel": { - "Assurances du personnel": { - "Assurance salaire garanti": {}, - "Assurances individuelles": {}, - "Assurances loi, responsabilit\u00e9 civile, chemin du travail": {} - }, - "Charges sociales des administrateurs, g\u00e9rants et commissaires": { - "Allocations familiales compl\u00e9mentaires pour non salari\u00e9s": {}, - "Divers": {}, - "Lois sociales pour ind\u00e9pendants": {} - }, - "Charges sociales diverses": { - "Allocations familiales compl\u00e9mentaires": {}, - "Jours f\u00e9ri\u00e9s pay\u00e9s": {}, - "Salaire hebdomadaire garanti": {} - } - }, - "Cotisations patronales d'assurances sociales": { - "Sur appointements et commissions": {}, - "Sur salaires": {} - }, - "Pensions de retraite et de survie": { - "Administrateurs et g\u00e9rants": {}, - "Personnel": {} - }, - "Primes patronales pour assurances extral\u00e9gales": {}, - "Provision pour p\u00e9cule de vacances": { - "Dotations": {}, - "Utilisations et reprises": {} - }, - "R\u00e9mun\u00e9rations et avantages sociaux directs": { - "Administrateurs ou g\u00e9rants": {}, - "Autres membres du personnel": {}, - "Employ\u00e9s": {}, - "Ouvriers": {}, - "Personnel de direction": {} - } - }, - "SERVICES ET BIENS DIVERS": { - "Annonces, publicit\u00e9, propagande et documentation": { - "Annonces et insertions": {}, - "Cadeaux \u00e0 la client\u00e8le": {}, - "Catalogues et imprim\u00e9s": {}, - "Documentation": {}, - "Echantillons": {}, - "Foires et expositions": {}, - "Missions et r\u00e9ceptions": {}, - "Primes": {} - }, - "Entretien et r\u00e9paration": {}, - "Fournitures faites \u00e0 l'entreprise": { - "Eau, gaz, \u00e9lectricit\u00e9, vapeur": { - "Eau": {}, - "Electricit\u00e9": {}, - "Gaz": {}, - "Vapeur": {} - }, - "Imprim\u00e9s et fournitures de bureau": {}, - "Livres, biblioth\u00e8que": {}, - "T\u00e9l\u00e9phone, t\u00e9l\u00e9grammes, t\u00e9lex, t\u00e9l\u00e9fax, frais postaux": { - "Frais postaux": {}, - "T\u00e9lex et t\u00e9l\u00e9fax": {}, - "T\u00e9l\u00e9grammes": {}, - "T\u00e9l\u00e9phone": {} - } - }, - "Loyers et charges locatives": { - "Charges locatives": {}, - "Loyers divers": {} - }, - "Personnel int\u00e9rimaire et personnes mises \u00e0 la disposition de l'entreprise": {}, - "R\u00e9mun\u00e9rations, primes pour assurances extral\u00e9gales": {}, - "R\u00e9tributions de tiers": { - "Assurances non relatives au personnel": { - "Assurance autos": {}, - "Assurance cr\u00e9dit": {}, - "Assurance incendie": {}, - "Assurance vol": {}, - "Assurances frais g\u00e9n\u00e9raux": {} - }, - "Divers": { - "Commissions aux tiers": {}, - "Cotisations aux groupements professionnels": {}, - "Dons, lib\u00e9ralit\u00e9s, ...": {}, - "Frais de contentieux": {}, - "Honoraires d'avocats, d'experts, etc ...": {}, - "Publications l\u00e9gales": {} - }, - "Personnel int\u00e9rimaire": {}, - "Redevances et royalties": { - "Autres redevances": {}, - "Redevances pour brevets, licences, marques, accessoires": {} - }, - "Transports et d\u00e9placements": { - "Transports de personnel": {}, - "Voyages, d\u00e9placements, repr\u00e9sentations": {} - } - }, - "Sous-traitants": { - "Quote-part b\u00e9n\u00e9ficiaire des coparticipants": {}, - "Sous-traitants d'associations momentan\u00e9es": {}, - "Sous-traitants pour activit\u00e9s propres": {} - } - }, - "TRANSFERTS AUX RESERVES IMMUNISEES": {}, - "root_type": "" - }, - "CLASSE 7. - PRODUITS": { - "AFFECTATION AUX RESULTATS": { - "B\u00e9n\u00e9fice report\u00e9 de l'exercice pr\u00e9c\u00e9dent": {}, - "Intervention d'associ\u00e9s": {}, - "Perte \u00e0 reporter": {}, - "Pr\u00e9l\u00e8vement sur le capital et les primes d'\u00e9mission": {}, - "Pr\u00e9l\u00e8vement sur les r\u00e9serves": {} - }, - "AUTRES PRODUITS D'EXPLOITATION": { - "Commissions et courtages": {}, - "Locations diverses \u00e0 caract\u00e8re professionnel": {}, - "Plus-values sur r\u00e9alisations courantes d'immobilisations corporelles": {}, - "Plus-values sur r\u00e9alisations de cr\u00e9ances commerciales": {}, - "Prestations de services": {}, - "Produits de services exploit\u00e9s dans l'int\u00e9r\u00eat du personnel": {}, - "Produits divers": { - "Bonis sur reprises d'emballages consign\u00e9s": {}, - "Bonis sur travaux en associations momentan\u00e9es": {} - }, - "Redevances pour brevets et licences": {}, - "Revenus des immeubles affect\u00e9s aux activit\u00e9s non professionnelles": {}, - "Subsides d'exploitation et montants compensatoires": {} - }, - "CHIFFRE D'AFFAIRES": { - "Facturations des travaux en cours": {}, - "Prestations de services": { - "Prestations de services dans les pays membres de la C.E.E.": {}, - "Prestations de services en Belgique": {}, - "Prestations de services en vue de l'exportation": {} - }, - "P\u00e9nalit\u00e9s et d\u00e9dits obtenus par l'entreprise": {}, - "Remises, ristournes et rabais accord\u00e9s": { - "Mali sur travaux factur\u00e9s aux associations momentan\u00e9es": {}, - "Sur prestations de services": {}, - "Sur ventes de d\u00e9chets et rebuts": {}, - "Sur ventes de marchandises": {}, - "Sur ventes de produits finis": {} - }, - "Ventes d'emballages r\u00e9cup\u00e9rables": {}, - "Ventes de d\u00e9chets et rebuts": { - "Ventes dans les pays membres de la C.E.E.": {}, - "Ventes en Belgique": {}, - "Ventes \u00e0 l'exportation": {} - }, - "Ventes de marchandises": { - "Ventes dans les pays membres de la C.E.E.": {}, - "Ventes en Belgique": {}, - "Ventes \u00e0 l'exportation": {} - }, - "Ventes de produits finis": { - "Ventes dans les pays membres de la C.E.E.": {}, - "Ventes en Belgique": {}, - "Ventes \u00e0 l'exportation": {} - } - }, - "PRODUCTION IMMOBILISEE": { - "En frais d'\u00e9tablissement": {}, - "En immobilisations corporelles": {}, - "En immobilisations en cours": {}, - "En immobilisations incorporelles": {} - }, - "PRODUITS EXCEPTIONNELS": { - "Autres produits exceptionnels": {}, - "Plus-values sur r\u00e9alisation d'actifs immobilis\u00e9s": { - "Sur immobilisations corporelles": {}, - "Sur immobilisations financi\u00e8res": {}, - "Sur immobilisations incorporelles": {} - }, - "Reprises d'amortissements et de r\u00e9ductions de valeur": { - "Sur immobilisations corporelles": {}, - "Sur immobilisations incorporelles": {} - }, - "Reprises de provisions pour risques et charges exceptionnelles": {}, - "Reprises de r\u00e9ductions de valeur sur immobilisations financi\u00e8res": {} - }, - "PRODUITS FINANCIERS": { - "Diff\u00e9rences de change": {}, - "Ecarts de conversion des devises": {}, - "Escomptes obtenus": {}, - "Plus-values sur r\u00e9alisations d'actifs circulants": {}, - "Produits des actifs circulants": {}, - "Produits des autres cr\u00e9ances": {}, - "Produits des immobilisations financi\u00e8res": { - "Revenus des actions": {}, - "Revenus des cr\u00e9ances \u00e0 plus d'un an": {}, - "Revenus des obligations": {} - }, - "Subsides en capital et en int\u00e9r\u00eats": {} - }, - "REGULARISATIONS D'IMPOTS ET REPRISES DE PROVISIONS FISCALES": { - "Imp\u00f4ts belges sur le r\u00e9sultat": { - "Reprises de provisions fiscales": {}, - "R\u00e9gularisations d'imp\u00f4ts dus ou vers\u00e9s": {}, - "R\u00e9gularisations d'imp\u00f4ts estim\u00e9s": {} - }, - "Imp\u00f4ts \u00e9trangers sur le r\u00e9sultat": {} - }, - "VARIATION DES STOCKS ET DES COMMANDES EN COURS D'EXECUTION": { - "Des commandes en cours d'ex\u00e9cution": { - "B\u00e9n\u00e9fices port\u00e9s en compte sur commandes en cours": { - "Sur commandes en cours d'ex\u00e9cution": {}, - "Sur travaux en cours des associations momentan\u00e9es": {} - }, - "Commandes en cours - Co\u00fbt de revient": { - "Co\u00fbt des commandes en cours d'ex\u00e9cution": {}, - "Co\u00fbt des travaux en cours des associations momentan\u00e9es": {} - } - }, - "Des en cours de fabrication": {}, - "Des immeubles construits destin\u00e9s \u00e0 la vente": {}, - "Des produits finis": {} - }, - "root_type": "" - } - } -} diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/be_minimum_genormaliseerd_rekeningstelsel_ondernemingen.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/be_minimum_genormaliseerd_rekeningstelsel_ondernemingen.json new file mode 100644 index 00000000000..21a48c71db7 --- /dev/null +++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/be_minimum_genormaliseerd_rekeningstelsel_ondernemingen.json @@ -0,0 +1,1597 @@ +{ + "country_code": "be", + "name": "België - Minimum genormaliseerd algemeen rekeningstelsel voor ondernemingen", + "tree": { + "KLASSE 1 : EIGEN VERMOGEN": { + "root_type": "Equity", + "Kapitaal": { + "Geplaatst kapitaal": { + "account_number": "100", + "account_type": "Equity" + }, + "Niet opgevraagd kapitaal (-)": { + "account_number": "101", + "account_type": "Equity" + }, + "account_number": "10", + "account_type": "Equity" + }, + "Inbreng buiten kapitaal": { + "Beschikbare inbreng buiten kapitaal": { + "Uitgiftepremie": { + "account_number": "1100", + "account_type": "Equity" + }, + "Andere": { + "account_number": "1109", + "account_type": "Equity" + }, + "account_number": "110", + "account_type": "Equity" + }, + "Onbeschikbare inbreng buiten kapitaal": { + "Uitgiftepremie": { + "account_number": "1110", + "account_type": "Equity" + }, + "Andere": { + "account_number": "1119", + "account_type": "Equity" + }, + "account_number": "111", + "account_type": "Equity" + }, + "account_number": "11", + "account_type": "Equity" + }, + "Herwaarderingsmeerwaarden": { + "Herwaarderingsmeerwaarden op immateriële vaste activa": { + "account_number": "120", + "account_type": "Equity" + }, + "Herwaarderingsmeerwaarden op materiële vaste activa": { + "account_number": "121", + "account_type": "Equity" + }, + "Herwaarderingsmeerwaarden op financiële vaste activa": { + "account_number": "122", + "account_type": "Equity" + }, + "Herwaarderingsmeerwaarden op voorraden": { + "account_number": "123", + "account_type": "Equity" + }, + "Terugneming van waardeverminderingen op geldbeleggingen": { + "account_number": "124", + "account_type": "Equity" + }, + "account_number": "12", + "account_type": "Equity" + }, + "Reserves": { + "Wettelijke reserves": { + "account_number": "130", + "account_type": "Equity" + }, + "Andere onbeschikbare reserves": { + "Statutair onbeschikbare reserves": { + "account_number": "1311", + "account_type": "Equity" + }, + "Reserve voor eigen aandelen": { + "account_number": "1312", + "account_type": "Equity" + }, + "Financiële steunverlening": { + "account_number": "1313", + "account_type": "Equity" + }, + "Overige": { + "account_number": "1319", + "account_type": "Equity" + }, + "account_number": "131", + "account_type": "Equity" + }, + "Belastingvrije reserves": { + "account_number": "132", + "account_type": "Equity" + }, + "Beschikbare reserves": { + "account_number": "133", + "account_type": "Equity" + }, + "account_number": "13", + "account_type": "Equity" + }, + "Overgedragen winst of Overgedragen verlies (-)": { + "account_number": "14", + "account_type": "Equity" + }, + "Kapitaalsubsidies": { + "account_number": "15", + "account_type": "Equity" + } + }, + "KLASSE 1 : VOORZIENINGEN, UITGESTELDE BELASTINGEN EN SCHULDEN OP MEER DAN ÉÉN JAAR": { + "root_type": "Liability", + "Voorzieningen en uitgestelde belastingen": { + "Voorzieningen voor pensioenen en soortgelijke verplichtingen": { + "account_number": "160", + "account_type": "Liability" + }, + "Voorzieningen voor belastingen": { + "account_number": "161", + "account_type": "Liability" + }, + "Voorzieningen voor grote herstellingswerken en grote onderhoudswerken": { + "account_number": "162", + "account_type": "Liability" + }, + "Voorzieningen voor milieuverplichtingen": { + "account_number": "163", + "account_type": "Liability" + }, + "Uitgestelde belastingen": { + "Uitgestelde belastingen op kapitaalsubsidies": { + "account_number": "1680", + "account_type": "Liability" + }, + "Uitgestelde belastingen op gerealiseerde meerwaarden op immateriële vaste activa": { + "account_number": "1681", + "account_type": "Liability" + }, + "Uitgestelde belastingen op gerealiseerde meerwaarden op materiële vaste activa": { + "account_number": "1682", + "account_type": "Liability" + }, + "Uitgestelde belastingen op gerealiseerde meerwaarden op effecten die zijn uitgegeven door de Belgische openbare sector": { + "account_number": "1687", + "account_type": "Liability" + }, + "Buitenlandse uitgestelde belastingen": { + "account_number": "1688", + "account_type": "Liability" + }, + "account_number": "168", + "account_type": "Liability" + }, + "account_number": "16", + "account_type": "Liability" + }, + "Schulden op meer dan één jaar": { + "Achtergestelde leningen": { + "Converteerbaar": { + "account_number": "1700", + "account_type": "Liability" + }, + "Niet converteerbaar": { + "account_number": "1701", + "account_type": "Liability" + }, + "account_number": "170", + "account_type": "Liability" + }, + "Niet-achtergestelde obligatieleningen": { + "Converteerbaar": { + "account_number": "1710", + "account_type": "Liability" + }, + "Niet converteerbaar": { + "account_number": "1711", + "account_type": "Liability" + }, + "account_number": "171", + "account_type": "Liability" + }, + "Leasingschulden en soortgelijke schulden": { + "account_number": "172", + "account_type": "Liability" + }, + "Kredietinstellingen": { + "Schulden op rekening": { + "account_number": "1730", + "account_type": "Liability" + }, + "Promessen": { + "account_number": "1731", + "account_type": "Liability" + }, + "Acceptkredieten": { + "account_number": "1732", + "account_type": "Liability" + }, + "account_number": "173", + "account_type": "Liability" + }, + "Overige leningen": { + "account_number": "174", + "account_type": "Liability" + }, + "Handelsschulden": { + "Leveranciers": { + "account_number": "1750", + "account_type": "Liability" + }, + "Te betalen wissels": { + "account_number": "1751", + "account_type": "Liability" + }, + "account_number": "175", + "account_type": "Liability" + }, + "Vooruitbetalingen op bestellingen": { + "account_number": "176", + "account_type": "Liability" + }, + "Borgtochten ontvangen in contanten": { + "account_number": "178", + "account_type": "Liability" + }, + "Overige schulden": { + "account_number": "179", + "account_type": "Liability" + }, + "account_number": "17", + "account_type": "Liability" + }, + "Voorschot aan de vennoten op de verdeling van het netto-actief (-)": { + "account_number": "19", + "account_type": "Liability" + } + }, + "KLASSE 2 : OPRICHTINGSKOSTEN, VASTE ACTIVA EN VORDERINGEN OP MEER DAN ÉÉN JAAR": { + "root_type": "Asset", + "Oprichtingskosten": { + "Kosten van oprichting, kapitaalverhoging of verhoging van de inbreng": { + "account_number": "200", + "account_type": "Fixed Asset" + }, + "Kosten bij uitgifte van leningen": { + "account_number": "201", + "account_type": "Fixed Asset" + }, + "Overige oprichtingskosten": { + "account_number": "202", + "account_type": "Fixed Asset" + }, + "Herstructureringskosten": { + "account_number": "204", + "account_type": "Fixed Asset" + }, + "account_number": "20", + "account_type": "Fixed Asset" + }, + "Immateriële vaste activa": { + "Kosten van onderzoek en ontwikkeling": { + "account_number": "210", + "account_type": "Fixed Asset" + }, + "Concessies, octrooien, licenties, know-how, merken en soortgelijke rechten": { + "account_number": "211", + "account_type": "Fixed Asset" + }, + "Goodwill": { + "account_number": "212", + "account_type": "Fixed Asset" + }, + "Vooruitbetalingen": { + "account_number": "213", + "account_type": "Fixed Asset" + }, + "Geboekte afschrijvingen en waardeverminderingen (-)": { + "account_number": "219", + "account_type": "Accumulated Depreciation" + }, + "account_number": "21", + "account_type": "Fixed Asset" + }, + "Terreinen en gebouwen": { + "Terreinen": { + "account_number": "220", + "account_type": "Fixed Asset" + }, + "Gebouwen": { + "account_number": "221", + "account_type": "Fixed Asset" + }, + "Bebouwde terreinen": { + "account_number": "222", + "account_type": "Fixed Asset" + }, + "Overige zakelijke rechten op onroerende goederen": { + "account_number": "223", + "account_type": "Fixed Asset" + }, + "Geboekte afschrijvingen en waardeverminderingen (-)": { + "account_number": "229", + "account_type": "Accumulated Depreciation" + }, + "account_number": "22", + "account_type": "Fixed Asset" + }, + "Installaties, machines en uitrusting": { + "account_number": "23", + "account_type": "Fixed Asset" + }, + "Meubilair en rollend materieel": { + "account_number": "24", + "account_type": "Fixed Asset" + }, + "Vaste activa in leasing of op grond van een soortgelijk recht": { + "Terreinen en gebouwen": { + "account_number": "250", + "account_type": "Fixed Asset" + }, + "Installaties, machines en uitrusting": { + "account_number": "251", + "account_type": "Fixed Asset" + }, + "Meubilair en rollend materieel": { + "account_number": "252", + "account_type": "Fixed Asset" + }, + "Geboekte afschrijvingen en waardeverminderingen (-)": { + "account_number": "259", + "account_type": "Accumulated Depreciation" + }, + "account_number": "25", + "account_type": "Fixed Asset" + }, + "Overige materiële vaste activa": { + "account_number": "26", + "account_type": "Fixed Asset" + }, + "Vaste activa in aanbouw en vooruitbetalingen": { + "account_number": "27", + "account_type": "Fixed Asset" + }, + "Financiële vaste activa": { + "Deelnemingen in verbonden ondernemingen": { + "Aanschaffingswaarde": { + "account_number": "2800", + "account_type": "Fixed Asset" + }, + "Nog te storten bedragen (-)": { + "account_number": "2801", + "account_type": "Fixed Asset" + }, + "Geboekte meerwaarden": { + "account_number": "2808", + "account_type": "Fixed Asset" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2809", + "account_type": "Fixed Asset" + }, + "account_number": "280", + "account_type": "Fixed Asset" + }, + "Vorderingen op verbonden ondernemingen": { + "Vorderingen op rekening": { + "account_number": "2810", + "account_type": "Fixed Asset" + }, + "Te innen wissels": { + "account_number": "2811", + "account_type": "Fixed Asset" + }, + "Vastrentende effecten": { + "account_number": "2812", + "account_type": "Fixed Asset" + }, + "Dubieuze debiteuren": { + "account_number": "2817", + "account_type": "Fixed Asset" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2819", + "account_type": "Fixed Asset" + }, + "account_number": "281", + "account_type": "Fixed Asset" + }, + "Deelnemingen in ondernemingen waarmee een deelnemingsverhouding bestaat": { + "Aanschaffingswaarde": { + "account_number": "2820", + "account_type": "Fixed Asset" + }, + "Nog te storten bedragen (-)": { + "account_number": "2821", + "account_type": "Fixed Asset" + }, + "Geboekte meerwaarden": { + "account_number": "2828", + "account_type": "Fixed Asset" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2829", + "account_type": "Fixed Asset" + }, + "account_number": "282", + "account_type": "Fixed Asset" + }, + "Vorderingen op ondernemingen waarmee een deelnemingsverhouding bestaat": { + "Vorderingen op rekening": { + "account_number": "2830", + "account_type": "Fixed Asset" + }, + "Te innen wissels": { + "account_number": "2831", + "account_type": "Fixed Asset" + }, + "Vastrentende effecten": { + "account_number": "2832", + "account_type": "Fixed Asset" + }, + "Dubieuze debiteuren": { + "account_number": "2837", + "account_type": "Fixed Asset" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2839", + "account_type": "Fixed Asset" + }, + "account_number": "283", + "account_type": "Fixed Asset" + }, + "Andere aandelen": { + "Aanschaffingswaarde": { + "account_number": "2840", + "account_type": "Fixed Asset" + }, + "Nog te storten bedragen (-)": { + "account_number": "2841", + "account_type": "Fixed Asset" + }, + "Geboekte meerwaarden": { + "account_number": "2848", + "account_type": "Fixed Asset" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2849", + "account_type": "Fixed Asset" + }, + "account_number": "284", + "account_type": "Fixed Asset" + }, + "Overige vorderingen": { + "Vorderingen op rekening": { + "account_number": "2850", + "account_type": "Fixed Asset" + }, + "Te innen wissels": { + "account_number": "2851", + "account_type": "Fixed Asset" + }, + "Vastrentende effecten": { + "account_number": "2852", + "account_type": "Fixed Asset" + }, + "Dubieuze debiteuren": { + "account_number": "2857", + "account_type": "Fixed Asset" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2859", + "account_type": "Fixed Asset" + }, + "account_number": "285", + "account_type": "Fixed Asset" + }, + "Borgtochten betaald in contanten": { + "account_number": "288", + "account_type": "Fixed Asset" + }, + "account_number": "28", + "account_type": "Fixed Asset" + }, + "Vorderingen op meer dan één jaar": { + "Handelsvorderingen": { + "Handelsdebiteuren": { + "account_number": "2900" + }, + "Te innen wissels": { + "account_number": "2901" + }, + "Vooruitbetalingen": { + "account_number": "2906" + }, + "Dubieuze debiteuren": { + "account_number": "2907" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2909" + }, + "account_number": "290" + }, + "Overige vorderingen": { + "Vorderingen op rekening": { + "account_number": "2910" + }, + "Te innen wissels": { + "account_number": "2911" + }, + "Dubieuze debiteuren": { + "account_number": "2917" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2919" + }, + "account_number": "291" + }, + "account_number": "29" + } + }, + "KLASSE 3 : VOORRADEN EN BESTELLINGEN IN UITVOERING": { + "root_type": "Asset", + "Grondstoffen": { + "Aanschaffingswaarde": { + "account_number": "300" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "309" + }, + "account_number": "30" + }, + "Hulpstoffen": { + "Aanschaffingswaarde": { + "account_number": "310" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "319" + }, + "account_number": "31" + }, + "Goederen in bewerking": { + "Aanschaffingswaarde": { + "account_number": "320" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "329" + }, + "account_number": "32" + }, + "Gereed product": { + "Aanschaffingswaarde": { + "account_number": "330" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "339" + }, + "account_number": "33" + }, + "Handelsgoederen": { + "Aanschaffingswaarde": { + "account_number": "340", + "account_type": "Stock" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "349" + }, + "account_number": "34", + "account_type": "Stock" + }, + "Onroerende goederen bestemd voor verkoop": { + "Aanschaffingswaarde": { + "account_number": "350" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "359" + }, + "account_number": "35" + }, + "Vooruitbetalingen op voorraadinkopen": { + "Vooruitbetalingen": { + "account_number": "360" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "369" + }, + "account_number": "36" + }, + "Bestellingen in uitvoering": { + "Aanschaffingswaarde": { + "account_number": "370" + }, + "Toegerekende winst": { + "account_number": "371" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "379" + }, + "account_number": "37" + }, + "Geleverde voorraad, niet gefactureerd": { + "account_type": "Stock Delivered But Not Billed" + } + }, + "KLASSE 4 : VORDERINGEN OP TEN HOOGSTE ÉÉN JAAR": { + "root_type": "Asset", + "Handelsvorderingen": { + "Handelsdebiteuren": { + "account_number": "400", + "account_type": "Receivable" + }, + "Te innen wissels": { + "account_number": "401", + "account_type": "Receivable" + }, + "Te innen opbrengsten": { + "account_number": "404", + "account_type": "Receivable" + }, + "Vooruitbetalingen": { + "account_number": "406" + }, + "Dubieuze debiteuren": { + "account_number": "407", + "account_type": "Receivable" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "409" + }, + "account_number": "40", + "account_type": "Receivable" + }, + "Overige vorderingen": { + "Opgevraagd, niet gestort kapitaal of inbreng": { + "account_number": "410" + }, + "Terug te vorderen btw": { + "account_number": "411", + "account_type": "Tax" + }, + "Terug te vorderen belastingen en voorheffingen": { + "Buitenlandse belastingen": { + "account_number": "4128" + }, + "account_number": "412" + }, + "Te innen opbrengsten": { + "account_number": "414" + }, + "Diverse vorderingen": { + "account_number": "416" + }, + "Dubieuze debiteuren": { + "account_number": "417" + }, + "Borgtochten betaald in contanten": { + "account_number": "418" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "419" + }, + "account_number": "41" + } + }, + "KLASSE 4 : SCHULDEN OP TEN HOOGSTE ÉÉN JAAR": { + "root_type": "Liability", + "Schulden op meer dan één jaar die binnen het jaar vervallen (16) (zelfde onderverdeling als 17)": { + "account_number": "42" + }, + "Financiële schulden": { + "Kredietinstellingen - Leningen op rekening met vaste termijn": { + "account_number": "430" + }, + "Kredietinstellingen - Promessen": { + "account_number": "431" + }, + "Kredietinstellingen - Acceptkredieten": { + "account_number": "432" + }, + "Kredietinstellingen - Schulden in rekening-courant": { + "account_number": "433" + }, + "Overige leningen": { + "account_number": "439" + }, + "account_number": "43" + }, + "Handelsschulden": { + "Leveranciers": { + "account_number": "440", + "account_type": "Payable" + }, + "Te betalen wissels": { + "account_number": "441", + "account_type": "Payable" + }, + "Te ontvangen facturen": { + "account_number": "444", + "account_type": "Stock Received But Not Billed" + }, + "account_number": "44", + "account_type": "Payable" + }, + "Schulden met betrekking tot belastingen, bezoldigingen en sociale lasten": { + "Geraamd bedrag der belastingschulden": { + "Buitenlandse belastingen en taksen": { + "account_number": "4508" + }, + "account_number": "450" + }, + "Te betalen btw": { + "account_number": "451", + "account_type": "Tax" + }, + "Te betalen belastingen en taksen": { + "Buitenlandse belastingen en taksen": { + "account_number": "4528" + }, + "account_number": "452" + }, + "Ingehouden voorheffingen": { + "account_number": "453" + }, + "Rijksdienst voor Sociale Zekerheid": { + "account_number": "454" + }, + "Bezoldigingen": { + "account_number": "455" + }, + "Vakantiegeld": { + "account_number": "456" + }, + "Andere sociale schulden": { + "account_number": "459" + }, + "account_number": "45" + }, + "Vooruitbetalingen op bestellingen": { + "account_number": "46" + }, + "Schulden uit de bestemming van het resultaat": { + "Dividenden en tantièmes over vorige boekjaren": { + "account_number": "470" + }, + "Dividenden over het boekjaar": { + "account_number": "471" + }, + "Tantièmes over het boekjaar": { + "account_number": "472" + }, + "Andere rechthebbenden": { + "account_number": "473" + }, + "account_number": "47" + }, + "Diverse schulden": { + "Vervallen obligaties en coupons": { + "account_number": "480" + }, + "Borgtochten ontvangen in contanten": { + "account_number": "488" + }, + "Andere diverse schulden": { + "account_number": "489" + }, + "account_number": "48" + }, + "Overlopende rekeningen": { + "Over te dragen kosten": { + "account_number": "490" + }, + "Verkregen opbrengsten": { + "account_number": "491" + }, + "Toe te rekenen kosten": { + "account_number": "492" + }, + "Over te dragen opbrengsten": { + "account_number": "493" + }, + "Wachtrekeningen": { + "account_number": "499" + }, + "account_number": "49" + } + }, + "KLASSE 5 : GELDBELEGGINGEN EN LIQUIDE MIDDELEN": { + "root_type": "Asset", + "Eigen aandelen": { + "account_number": "50" + }, + "Aandelen en geldbeleggingen andere dan vastrentende beleggingen": { + "Aanschaffingswaarde": { + "Aandelen": { + "account_number": "5100" + }, + "Geldbeleggingen andere dan vastrentende beleggingen": { + "account_number": "5101" + }, + "account_number": "510" + }, + "Niet-opgevraagde bedragen (-)": { + "Aandelen": { + "account_number": "5110" + }, + "account_number": "511" + }, + "Geboekte waardeverminderingen (-)": { + "Aandelen": { + "account_number": "5190" + }, + "Geldbeleggingen andere dan vastrentende beleggingen": { + "account_number": "5191" + }, + "account_number": "519" + }, + "account_number": "51" + }, + "Vastrentende effecten": { + "Aanschaffingswaarde": { + "account_number": "520" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "529" + }, + "account_number": "52" + }, + "Termijndeposito's": { + "Op meer dan één jaar": { + "account_number": "530" + }, + "Op meer dan één maand en op ten hoogste één jaar": { + "account_number": "531" + }, + "Op ten hoogste één maand": { + "account_number": "532" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "539" + }, + "account_number": "53" + }, + "Te incasseren vervallen waarden": { + "account_number": "54" + }, + "Kredietinstellingen": { + "Bank": { + "account_number": "5500", + "account_type": "Bank" + }, + "account_number": "55", + "account_type": "Bank" + }, + "Kassen": { + "Kassen-zegels": { + "account_number": "578", + "account_type": "Cash" + }, + "account_number": "57", + "account_type": "Cash" + }, + "Interne overboekingen": { + "account_number": "58", + "account_type": "Temporary" + } + }, + "KLASSE 6 : KOSTEN": { + "root_type": "Expense", + "Handelsgoederen, grond- en hulpstoffen": { + "Aankopen van grondstoffen": { + "account_number": "600", + "account_type": "Expense Account" + }, + "Aankopen van hulpstoffen": { + "account_number": "601", + "account_type": "Expense Account" + }, + "Aankopen van diensten, werk en studies": { + "account_number": "602", + "account_type": "Expense Account" + }, + "Algemene onderaannemingen": { + "account_number": "603", + "account_type": "Expense Account" + }, + "Aankopen van handelsgoederen": { + "account_number": "604", + "account_type": "Cost of Goods Sold" + }, + "Aankopen van onroerende goederen bestemd voor verkoop": { + "account_number": "605", + "account_type": "Expense Account" + }, + "Ontvangen kortingen, ristorno's en rabatten (-)": { + "account_number": "608", + "account_type": "Expense Account" + }, + "Voorraadwijzigingen": { + "van grondstoffen": { + "account_number": "6090", + "account_type": "Stock Adjustment" + }, + "van hulpstoffen": { + "account_number": "6091", + "account_type": "Stock Adjustment" + }, + "van handelsgoederen": { + "account_number": "6094", + "account_type": "Stock Adjustment" + }, + "van gekochte onroerende goederen bestemd voor verkoop": { + "account_number": "6095", + "account_type": "Stock Adjustment" + }, + "account_number": "609", + "account_type": "Stock Adjustment" + }, + "account_number": "60", + "account_type": "Expense Account" + }, + "Diensten en diverse goederen": { + "Uitzendkrachten en personen ter beschikking gesteld van de onderneming": { + "account_number": "617", + "account_type": "Expense Account" + }, + "Bezoldigingen en pensioenen van bestuurders, zaakvoerders en werkende vennoten, buiten arbeidsovereenkomst": { + "account_number": "618", + "account_type": "Expense Account" + }, + "Aankoopkosten begrepen in de waarde van de voorraden": { + "account_type": "Expenses Included In Valuation" + }, + "account_number": "61", + "account_type": "Expense Account" + }, + "Bezoldigingen, sociale lasten en pensioenen": { + "Bezoldigingen en rechtstreekse sociale voordelen": { + "Bestuurders of zaakvoerders": { + "account_number": "6200", + "account_type": "Expense Account" + }, + "Directiepersoneel": { + "account_number": "6201", + "account_type": "Expense Account" + }, + "Bedienden": { + "account_number": "6202", + "account_type": "Expense Account" + }, + "Arbeiders": { + "account_number": "6203", + "account_type": "Expense Account" + }, + "Andere personeelsleden": { + "account_number": "6204", + "account_type": "Expense Account" + }, + "account_number": "620", + "account_type": "Expense Account" + }, + "Werkgeversbijdragen voor sociale verzekeringen": { + "account_number": "621", + "account_type": "Expense Account" + }, + "Werkgeverspremies voor bovenwettelijke verzekeringen": { + "account_number": "622", + "account_type": "Expense Account" + }, + "Andere personeelskosten": { + "account_number": "623", + "account_type": "Expense Account" + }, + "Ouderdoms- en overlevingspensioenen": { + "Bestuurders of zaakvoerders": { + "account_number": "6240", + "account_type": "Expense Account" + }, + "Personeel": { + "account_number": "6241", + "account_type": "Expense Account" + }, + "account_number": "624", + "account_type": "Expense Account" + }, + "account_number": "62", + "account_type": "Expense Account" + }, + "Afschrijvingen, waardeverminderingen en voorzieningen voor risico's": { + "Afschrijvingen en waardeverminderingen op vaste activa-toevoeging": { + "Afschrijvingen op oprichtingskosten": { + "account_number": "6300", + "account_type": "Depreciation" + }, + "Afschrijvingen op immateriële vaste activa": { + "account_number": "6301", + "account_type": "Depreciation" + }, + "Afschrijvingen op materiële vaste activa": { + "account_number": "6302", + "account_type": "Depreciation" + }, + "Waardeverminderingen op immateriële vaste activa": { + "account_number": "6308", + "account_type": "Depreciation" + }, + "Waardeverminderingen op materiële vaste activa": { + "account_number": "6309", + "account_type": "Depreciation" + }, + "account_number": "630", + "account_type": "Depreciation" + }, + "Waardeverminderingen op voorraden": { + "Toevoeging": { + "account_number": "6310", + "account_type": "Depreciation" + }, + "Terugneming (-)": { + "account_number": "6311", + "account_type": "Depreciation" + }, + "account_number": "631", + "account_type": "Depreciation" + }, + "Waardeverminderingen op bestellingen in uitvoering": { + "Toevoeging": { + "account_number": "6320", + "account_type": "Depreciation" + }, + "Terugneming (-)": { + "account_number": "6321", + "account_type": "Depreciation" + }, + "account_number": "632", + "account_type": "Depreciation" + }, + "Waardeverminderingen op handelsvorderingen op meer dan één jaar": { + "Toevoeging": { + "account_number": "6330", + "account_type": "Depreciation" + }, + "Terugneming (-)": { + "account_number": "6331", + "account_type": "Depreciation" + }, + "account_number": "633", + "account_type": "Depreciation" + }, + "Waardeverminderingen op handelsvorderingen op ten hoogste één jaar": { + "Toevoeging": { + "account_number": "6340", + "account_type": "Depreciation" + }, + "Terugneming (-)": { + "account_number": "6341", + "account_type": "Depreciation" + }, + "account_number": "634", + "account_type": "Depreciation" + }, + "Voorzieningen voor pensioenen en soortgelijke verplichtingen": { + "Toevoeging": { + "account_number": "6350", + "account_type": "Depreciation" + }, + "Besteding en terugneming (-)": { + "account_number": "6351", + "account_type": "Depreciation" + }, + "account_number": "635", + "account_type": "Depreciation" + }, + "Voorzieningen voor grote herstellingswerken en grote onderhoudswerken": { + "Toevoeging": { + "account_number": "6360", + "account_type": "Depreciation" + }, + "Besteding en terugneming (-)": { + "account_number": "6361", + "account_type": "Depreciation" + }, + "account_number": "636", + "account_type": "Depreciation" + }, + "Voorzieningen voor milieuverplichtingen": { + "Toevoeging": { + "account_number": "6370", + "account_type": "Depreciation" + }, + "Besteding en terugneming (-)": { + "account_number": "6371", + "account_type": "Depreciation" + }, + "account_number": "637", + "account_type": "Depreciation" + }, + "Voorzieningen voor andere risico's en kosten": { + "Toevoeging": { + "account_number": "6380", + "account_type": "Expense Account" + }, + "Besteding en terugneming (-)": { + "account_number": "6381", + "account_type": "Expense Account" + }, + "account_number": "638", + "account_type": "Expense Account" + }, + "account_number": "63", + "account_type": "Expense Account" + }, + "Andere bedrijfskosten": { + "Bedrijfsbelastingen": { + "account_number": "640", + "account_type": "Expense Account" + }, + "Minderwaarden op de courante realisatie van vaste activa": { + "account_number": "641", + "account_type": "Expense Account" + }, + "Minderwaarden op de realisatie van handelsvorderingen": { + "account_number": "642", + "account_type": "Expense Account" + }, + "Diverse bedrijfskosten (643 tot 648)": { + "account_number": "643", + "account_type": "Expense Account" + }, + "Als herstructureringskosten geactiveerde bedrijfskosten (-)": { + "account_number": "649", + "account_type": "Expense Account" + }, + "account_number": "64", + "account_type": "Expense Account" + }, + "Financiële kosten": { + "Kosten van schulden": { + "Rente, commissies en kosten verbonden aan schulden": { + "account_number": "6500", + "account_type": "Expense Account" + }, + "Afschrijving van kosten bij uitgifte van leningen": { + "account_number": "6501", + "account_type": "Expense Account" + }, + "Geactiveerde intercalaire interesten (-)": { + "account_number": "6502", + "account_type": "Expense Account" + }, + "account_number": "650", + "account_type": "Expense Account" + }, + "Waardeverminderingen op vlottende activa": { + "Toevoeging": { + "account_number": "6510", + "account_type": "Expense Account" + }, + "Terugneming (-)": { + "account_number": "6511", + "account_type": "Expense Account" + }, + "account_number": "651", + "account_type": "Expense Account" + }, + "Minderwaarden op de realisatie van vlottende activa": { + "account_number": "652", + "account_type": "Expense Account" + }, + "Discontokosten op vorderingen": { + "account_number": "653", + "account_type": "Expense Account" + }, + "Wisselresultaten": { + "account_number": "654", + "account_type": "Expense Account" + }, + "Resultaten uit de omrekening van vreemde valuta": { + "account_number": "655", + "account_type": "Expense Account" + }, + "Voorzieningen met financieel karakter": { + "Toevoegingen": { + "account_number": "6560", + "account_type": "Expense Account" + }, + "Bestedingen en terugnemingen (-)": { + "account_number": "6561", + "account_type": "Expense Account" + }, + "account_number": "656", + "account_type": "Expense Account" + }, + "Diverse financiële kosten (657 tot 658)": { + "account_number": "657", + "account_type": "Expense Account" + }, + "Als herstructureringskosten geactiveerde financiële kosten (-)": { + "account_number": "659", + "account_type": "Expense Account" + }, + "account_number": "65", + "account_type": "Expense Account" + }, + "Niet-recurrente bedrijfs- of financiële kosten": { + "Niet-recurrente afschrijvingen en waardeverminderingen (toevoeging)": { + "op oprichtingskosten": { + "account_number": "6600", + "account_type": "Expense Account" + }, + "op immateriële vaste activa": { + "account_number": "6601", + "account_type": "Expense Account" + }, + "op materiële vaste activa": { + "account_number": "6602", + "account_type": "Expense Account" + }, + "account_number": "660", + "account_type": "Expense Account" + }, + "Waardeverminderingen op financiële vaste activa (toevoeging)": { + "account_number": "661", + "account_type": "Expense Account" + }, + "Voorzieningen voor niet-recurrente risico's en kosten": { + "Voorzieningen voor niet-recurrente bedrijfsrisico's en -kosten": { + "Toevoeging": { + "account_number": "66200", + "account_type": "Expense Account" + }, + "Besteding (-)": { + "account_number": "66201", + "account_type": "Expense Account" + }, + "account_number": "6620", + "account_type": "Expense Account" + }, + "Voorzieningen voor niet-recurrente financiële risico's en -kosten": { + "Toevoeging": { + "account_number": "66210", + "account_type": "Expense Account" + }, + "Besteding (-)": { + "account_number": "66211", + "account_type": "Expense Account" + }, + "account_number": "6621", + "account_type": "Expense Account" + }, + "account_number": "662", + "account_type": "Expense Account" + }, + "Minderwaarden op de realisatie van vaste activa": { + "Minderwaarden op de realisatie van immateriële en materiële vaste activa": { + "account_number": "6630", + "account_type": "Expense Account" + }, + "Minderwaarden op de realisatie van financiële vaste activa": { + "account_number": "6631", + "account_type": "Expense Account" + }, + "account_number": "663", + "account_type": "Expense Account" + }, + "Andere niet-recurrente bedrijfskosten (664 tot 667)": { + "account_number": "664", + "account_type": "Expense Account" + }, + "Andere niet-recurrente financiële kosten": { + "account_number": "668", + "account_type": "Expense Account" + }, + "Als herstructureringskosten geactiveerde niet-recurrente bedrijfskosten (-)": { + "account_number": "6690", + "account_type": "Expense Account" + }, + "Als herstructureringskosten geactiveerde niet-recurrente financiële kosten (-)": { + "account_number": "6691", + "account_type": "Expense Account" + }, + "account_number": "66", + "account_type": "Expense Account" + }, + "Belastingen op het resultaat": { + "Belgische belastingen op het resultaat van het boekjaar": { + "Verschuldigde of gestorte belastingen en voorheffingen": { + "account_number": "6700", + "account_type": "Expense Account" + }, + "Geactiveerde overschotten van betaalde belastingen en voorheffingen (-)": { + "account_number": "6701", + "account_type": "Expense Account" + }, + "Geraamde belastingen": { + "account_number": "6702", + "account_type": "Expense Account" + }, + "account_number": "670", + "account_type": "Expense Account" + }, + "Belgische belastingen op het resultaat van vorige boekjaren": { + "Verschuldigde of gestorte belastingsupplementen": { + "account_number": "6710", + "account_type": "Expense Account" + }, + "Geraamde belastingsupplementen": { + "account_number": "6711", + "account_type": "Expense Account" + }, + "Gevormde fiscale voorzieningen": { + "account_number": "6712", + "account_type": "Expense Account" + }, + "account_number": "671", + "account_type": "Expense Account" + }, + "Buitenlandse belastingen op het resultaat van het boekjaar": { + "account_number": "672", + "account_type": "Expense Account" + }, + "Buitenlandse belastingen op het resultaat van vorige boekjaren": { + "account_number": "673", + "account_type": "Expense Account" + }, + "account_number": "67", + "account_type": "Expense Account" + }, + "Overboeking naar de uitgestelde belastingen en naar de belastingvrije reserves": { + "Overboeking naar de uitgestelde belastingen": { + "account_number": "680", + "account_type": "Expense Account" + }, + "Overboeking naar de belastingvrije reserves": { + "account_number": "689", + "account_type": "Expense Account" + }, + "account_number": "68", + "account_type": "Expense Account" + }, + "Resultatenverwerking": { + "Overgedragen verlies van het vorige boekjaar": { + "account_number": "690", + "account_type": "Expense Account" + }, + "Toevoeging aan de inbreng": { + "account_number": "691", + "account_type": "Expense Account" + }, + "Toevoeging aan de reserves": { + "Toevoeging aan de wettelijke reserve": { + "account_number": "6920", + "account_type": "Expense Account" + }, + "Toevoeging aan de overige reserves": { + "account_number": "6921", + "account_type": "Expense Account" + }, + "account_number": "692", + "account_type": "Expense Account" + }, + "Over te dragen winst": { + "account_number": "693", + "account_type": "Expense Account" + }, + "Vergoeding van de inbreng": { + "account_number": "694", + "account_type": "Expense Account" + }, + "Bestuurders of zaakvoerders": { + "account_number": "695", + "account_type": "Expense Account" + }, + "Werknemers": { + "account_number": "696", + "account_type": "Expense Account" + }, + "Andere rechthebbenden": { + "account_number": "697", + "account_type": "Expense Account" + }, + "account_number": "69", + "account_type": "Expense Account" + } + }, + "KLASSE 7 : OPBRENGSTEN": { + "root_type": "Income", + "Omzet": { + "Toegekende kortingen, ristorno's en rabatten (-)": { + "account_number": "708", + "account_type": "Income Account" + }, + "account_number": "70", + "account_type": "Income Account" + }, + "Wijzigingen in de voorraden en in de bestellingen in uitvoering": { + "In de voorraad goederen in bewerking": { + "account_number": "712", + "account_type": "Income Account" + }, + "In de voorraad gereed product": { + "account_number": "713", + "account_type": "Income Account" + }, + "In de voorraad onroerende goederen bestemd voor verkoop": { + "account_number": "715", + "account_type": "Income Account" + }, + "In de bestellingen in uitvoering": { + "Aanschaffingswaarde": { + "account_number": "7170", + "account_type": "Income Account" + }, + "Toegerekende winst": { + "account_number": "7171", + "account_type": "Income Account" + }, + "account_number": "717", + "account_type": "Income Account" + }, + "account_number": "71", + "account_type": "Income Account" + }, + "Geproduceerde vaste activa": { + "account_number": "72", + "account_type": "Income Account" + }, + "Andere bedrijfsopbrengsten": { + "Bedrijfssubsidies en compenserende bedragen": { + "account_number": "740", + "account_type": "Income Account" + }, + "Meerwaarden op de courante realisatie van materiële vaste activa": { + "account_number": "741", + "account_type": "Income Account" + }, + "Meerwaarden op de realisatie van handelsvorderingen": { + "account_number": "742", + "account_type": "Income Account" + }, + "Diverse bedrijfsopbrengsten (743 tot 749)": { + "account_number": "743", + "account_type": "Income Account" + }, + "account_number": "74", + "account_type": "Income Account" + }, + "Financiële opbrengsten": { + "Opbrengsten uit financiële vaste activa": { + "account_number": "750", + "account_type": "Income Account" + }, + "Opbrengsten uit vlottende activa": { + "account_number": "751", + "account_type": "Income Account" + }, + "Meerwaarden op de realisatie van vlottende activa": { + "account_number": "752", + "account_type": "Income Account" + }, + "Kapitaal- en interestsubsidies": { + "account_number": "753", + "account_type": "Income Account" + }, + "Wisselresultaten": { + "account_number": "754", + "account_type": "Income Account" + }, + "Resultaten uit de omrekening van vreemde valuta": { + "account_number": "755", + "account_type": "Income Account" + }, + "Diverse financiële opbrengsten (756 tot 759)": { + "account_number": "756", + "account_type": "Income Account" + }, + "account_number": "75", + "account_type": "Income Account" + }, + "Niet-recurrente bedrijfs- of financiële opbrengsten": { + "Terugneming van afschrijvingen en waardeverminderingen": { + "op immateriële vaste activa": { + "account_number": "7600", + "account_type": "Income Account" + }, + "op materiële vaste activa": { + "account_number": "7601", + "account_type": "Income Account" + }, + "account_number": "760", + "account_type": "Income Account" + }, + "Terugneming van waardeverminderingen op financiële vaste activa": { + "account_number": "761", + "account_type": "Income Account" + }, + "Terugneming van voorzieningen voor niet-recurrente risico's en kosten": { + "Terugneming van voorzieningen voor niet-recurrente bedrijfsrisico's en -kosten": { + "account_number": "7620", + "account_type": "Income Account" + }, + "Terugneming van voorzieningen voor niet-recurrente financiële risico's en -kosten": { + "account_number": "7621", + "account_type": "Income Account" + }, + "account_number": "762", + "account_type": "Income Account" + }, + "Meerwaarden op de realisatie van vaste activa": { + "Meerwaarde op de realisatie van immateriële en materiële vaste activa": { + "account_number": "7630", + "account_type": "Income Account" + }, + "Meerwaarde op de realisatie van financiële vaste activa": { + "account_number": "7631", + "account_type": "Income Account" + }, + "account_number": "763", + "account_type": "Income Account" + }, + "Andere niet-recurrente bedrijfsopbrengsten (764 tot 768)": { + "account_number": "764", + "account_type": "Income Account" + }, + "Andere niet-recurrente financiële opbrengsten": { + "account_number": "769", + "account_type": "Income Account" + }, + "account_number": "76", + "account_type": "Income Account" + }, + "Regularisering van belastingen en terugneming van fiscale voorzieningen": { + "Belgische belastingen op het resultaat": { + "Regularisering van verschuldigde of betaalde belastingen": { + "account_number": "7710", + "account_type": "Income Account" + }, + "Regularisering van geraamde belastingen": { + "account_number": "7711", + "account_type": "Income Account" + }, + "Terugneming van fiscale voorzieningen": { + "account_number": "7712", + "account_type": "Income Account" + }, + "account_number": "771", + "account_type": "Income Account" + }, + "Buitenlandse belastingen op het resultaat": { + "account_number": "773", + "account_type": "Income Account" + }, + "account_number": "77", + "account_type": "Income Account" + }, + "Onttrekkingen aan de belastingvrije reserves en uitgestelde belastingen": { + "Onttrekkingen aan de uitgestelde belastingen": { + "account_number": "780", + "account_type": "Income Account" + }, + "Onttrekkingen aan de belastingvrije reserves": { + "account_number": "789", + "account_type": "Income Account" + }, + "account_number": "78", + "account_type": "Income Account" + }, + "Resultaatverwerking": { + "Overgedragen winst van het vorige boekjaar": { + "account_number": "790", + "account_type": "Income Account" + }, + "Onttrekking aan de inbreng": { + "account_number": "791", + "account_type": "Income Account" + }, + "Onttrekking aan de reserves": { + "account_number": "792", + "account_type": "Income Account" + }, + "Over te dragen verlies": { + "account_number": "793", + "account_type": "Income Account" + }, + "Tussenkomst van vennoten (of van de eigenaar) in het verlies": { + "account_number": "794", + "account_type": "Income Account" + }, + "account_number": "79", + "account_type": "Income Account" + } + } + } +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/be_minimum_genormaliseerd_rekeningstelsel_verenigingen_stichtingen.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/be_minimum_genormaliseerd_rekeningstelsel_verenigingen_stichtingen.json new file mode 100644 index 00000000000..d94c3552e40 --- /dev/null +++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/be_minimum_genormaliseerd_rekeningstelsel_verenigingen_stichtingen.json @@ -0,0 +1,1478 @@ +{ + "country_code": "be", + "name": "België - Minimum genormaliseerd algemeen rekeningstelsel voor verenigingen en stichtingen", + "tree": { + "KLASSE 1 : VERENIGINGSFONDS EN STICHTINGSFONDS": { + "root_type": "Equity", + "Fondsen van de vereniging of stichting": { + "account_number": "10", + "account_type": "Equity" + }, + "Herwaarderingsmeerwaarden": { + "Herwaarderingsmeerwaarden op immateriële vaste activa": { + "account_number": "120", + "account_type": "Equity" + }, + "Herwaarderingsmeerwaarden op materiële vaste activa": { + "account_number": "121", + "account_type": "Equity" + }, + "Herwaarderingsmeerwaarden op financiële vaste activa": { + "account_number": "122", + "account_type": "Equity" + }, + "Terugneming van waardeverminderingen op geldbeleggingen": { + "account_number": "124", + "account_type": "Equity" + }, + "account_number": "12", + "account_type": "Equity" + }, + "Bestemde fondsen en andere reserves": { + "Fondsen bestemd voor investeringen": { + "account_number": "130", + "account_type": "Equity" + }, + "Fondsen bestemd voor sociaal passief": { + "account_number": "131", + "account_type": "Equity" + }, + "Belastingvrije reserves": { + "account_number": "132", + "account_type": "Equity" + }, + "Andere bestemde fondsen en andere reserves": { + "account_number": "139", + "account_type": "Equity" + }, + "account_number": "13", + "account_type": "Equity" + }, + "Overgedragen resultaat (+)(-)": { + "account_number": "14", + "account_type": "Equity" + }, + "Kapitaalsubsidies": { + "account_number": "15", + "account_type": "Equity" + } + }, + "KLASSE 1 : VOORZIENINGEN, UITGESTELDE BELASTINGEN EN SCHULDEN OP MEER DAN ÉÉN JAAR": { + "root_type": "Liability", + "Voorzieningen en uitgestelde belastingen": { + "Voorzieningen voor pensioenen en soortgelijke verplichtingen": { + "account_number": "160", + "account_type": "Liability" + }, + "Voorzieningen voor belastingen": { + "account_number": "161", + "account_type": "Liability" + }, + "Voorzieningen voor grote herstellingswerken en grote onderhoudswerken": { + "account_number": "162", + "account_type": "Liability" + }, + "Voorzieningen voor milieuverplichtingen": { + "account_number": "163", + "account_type": "Liability" + }, + "Voorzieningen voor terug te betalen subsidies, legaten en schenkingen met terugnemingsrecht": { + "account_number": "167", + "account_type": "Liability" + }, + "Uitgestelde belastingen": { + "account_number": "168", + "account_type": "Liability" + }, + "account_number": "16", + "account_type": "Liability" + }, + "Schulden op meer dan één jaar": { + "Achtergestelde leningen": { + "account_number": "170", + "account_type": "Liability" + }, + "Niet-achtergestelde obligatieleningen": { + "account_number": "171", + "account_type": "Liability" + }, + "Leasingschulden en soortgelijke schulden": { + "account_number": "172", + "account_type": "Liability" + }, + "Kredietinstellingen": { + "Schulden op rekening": { + "account_number": "1730", + "account_type": "Liability" + }, + "Promessen": { + "account_number": "1731", + "account_type": "Liability" + }, + "Acceptkredieten": { + "account_number": "1732", + "account_type": "Liability" + }, + "account_number": "173", + "account_type": "Liability" + }, + "Overige leningen": { + "account_number": "174", + "account_type": "Liability" + }, + "Handelsschulden": { + "Leveranciers": { + "account_number": "1750", + "account_type": "Liability" + }, + "Te betalen wissels": { + "account_number": "1751", + "account_type": "Liability" + }, + "account_number": "175", + "account_type": "Liability" + }, + "Vooruitbetalingen op bestellingen": { + "account_number": "176", + "account_type": "Liability" + }, + "Borgtochten in contanten": { + "account_number": "178", + "account_type": "Liability" + }, + "Overige schulden": { + "Rentedragend": { + "account_number": "1790", + "account_type": "Liability" + }, + "Niet-rentedragend of gekoppeld aan een abnormaal lage rente": { + "account_number": "1791", + "account_type": "Liability" + }, + "account_number": "179", + "account_type": "Liability" + }, + "account_number": "17", + "account_type": "Liability" + } + }, + "KLASSE 2 : OPRICHTINGSKOSTEN, VASTE ACTIVA EN VORDERINGEN OP MEER DAN ÉÉN JAAR": { + "root_type": "Asset", + "Oprichtingskosten": { + "Kosten van oprichting": { + "account_number": "200", + "account_type": "Fixed Asset" + }, + "Kosten bij uitgifte van leningen": { + "account_number": "201", + "account_type": "Fixed Asset" + }, + "Overige oprichtingskosten": { + "account_number": "202", + "account_type": "Fixed Asset" + }, + "Herstructureringskosten": { + "account_number": "204", + "account_type": "Fixed Asset" + }, + "account_number": "20", + "account_type": "Fixed Asset" + }, + "Immateriële vaste activa": { + "Kosten van onderzoek en ontwikkeling": { + "account_number": "210", + "account_type": "Fixed Asset" + }, + "Concessies, octrooien, licenties, knowhow, merken en soortgelijke rechten": { + "account_number": "211", + "account_type": "Fixed Asset" + }, + "Goodwill": { + "account_number": "212", + "account_type": "Fixed Asset" + }, + "Vooruitbetalingen": { + "account_number": "213", + "account_type": "Fixed Asset" + }, + "Geboekte afschrijvingen en waardeverminderingen (-)": { + "account_number": "219", + "account_type": "Accumulated Depreciation" + }, + "account_number": "21", + "account_type": "Fixed Asset" + }, + "Terreinen en gebouwen": { + "Terreinen": { + "account_number": "220", + "account_type": "Fixed Asset" + }, + "Gebouwen": { + "account_number": "221", + "account_type": "Fixed Asset" + }, + "Bebouwde terreinen": { + "account_number": "222", + "account_type": "Fixed Asset" + }, + "Overige zakelijke rechten op onroerende goederen": { + "account_number": "223", + "account_type": "Fixed Asset" + }, + "Geboekte afschrijvingen en waardeverminderingen (-)": { + "account_number": "229", + "account_type": "Accumulated Depreciation" + }, + "account_number": "22", + "account_type": "Fixed Asset" + }, + "Installaties, machines en uitrusting": { + "account_number": "23", + "account_type": "Fixed Asset" + }, + "Meubilair en rollend materieel": { + "account_number": "24", + "account_type": "Fixed Asset" + }, + "Vaste activa in leasing of op grond van soortgelijke rechten": { + "Terreinen en gebouwen": { + "account_number": "250", + "account_type": "Fixed Asset" + }, + "Installaties, machines en uitrusting": { + "account_number": "251", + "account_type": "Fixed Asset" + }, + "Meubilair en rollend materieel": { + "account_number": "252", + "account_type": "Fixed Asset" + }, + "Geboekte afschrijvingen en waardeverminderingen (-)": { + "account_number": "259", + "account_type": "Accumulated Depreciation" + }, + "account_number": "25", + "account_type": "Fixed Asset" + }, + "Overige materiële vaste activa": { + "account_number": "26", + "account_type": "Fixed Asset" + }, + "Materiële activa in aanbouw en vooruitbetalingen": { + "account_number": "27", + "account_type": "Fixed Asset" + }, + "Financiële vaste activa": { + "Deelnemingen in verbonden vennootschappen": { + "Aanschaffingswaarde": { + "account_number": "2800", + "account_type": "Fixed Asset" + }, + "Nog te storten bedragen (-)": { + "account_number": "2801", + "account_type": "Fixed Asset" + }, + "Geboekte meerwaarden": { + "account_number": "2808", + "account_type": "Fixed Asset" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2809", + "account_type": "Fixed Asset" + }, + "account_number": "280", + "account_type": "Fixed Asset" + }, + "Vorderingen op verbonden entiteiten": { + "Vorderingen op rekening": { + "account_number": "2810", + "account_type": "Fixed Asset" + }, + "Te innen wissels": { + "account_number": "2811", + "account_type": "Fixed Asset" + }, + "Vastrentende effecten": { + "account_number": "2812", + "account_type": "Fixed Asset" + }, + "Dubieuze debiteuren": { + "account_number": "2817", + "account_type": "Fixed Asset" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2819", + "account_type": "Fixed Asset" + }, + "account_number": "281", + "account_type": "Fixed Asset" + }, + "Deelnemingen in vennootschappen waarmee een deelnemingsverhouding bestaat": { + "Aanschaffingswaarde": { + "account_number": "2820", + "account_type": "Fixed Asset" + }, + "Nog te storten bedragen (-)": { + "account_number": "2821", + "account_type": "Fixed Asset" + }, + "Geboekte meerwaarden": { + "account_number": "2828", + "account_type": "Fixed Asset" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2829", + "account_type": "Fixed Asset" + }, + "account_number": "282", + "account_type": "Fixed Asset" + }, + "Vorderingen op vennootschappen waarmee een deelnemingsverhouding bestaat": { + "Vorderingen op rekening": { + "account_number": "2830", + "account_type": "Fixed Asset" + }, + "Te innen wissels": { + "account_number": "2831", + "account_type": "Fixed Asset" + }, + "Vastrentende effecten": { + "account_number": "2832", + "account_type": "Fixed Asset" + }, + "Dubieuze debiteuren": { + "account_number": "2837", + "account_type": "Fixed Asset" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2839", + "account_type": "Fixed Asset" + }, + "account_number": "283", + "account_type": "Fixed Asset" + }, + "Andere aandelen": { + "Aanschaffingswaarde": { + "account_number": "2840", + "account_type": "Fixed Asset" + }, + "Nog te storten bedragen (-)": { + "account_number": "2841", + "account_type": "Fixed Asset" + }, + "Geboekte meerwaarden": { + "account_number": "2848", + "account_type": "Fixed Asset" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2849", + "account_type": "Fixed Asset" + }, + "account_number": "284", + "account_type": "Fixed Asset" + }, + "Overige vorderingen": { + "Vorderingen op rekening": { + "account_number": "2850", + "account_type": "Fixed Asset" + }, + "Te innen wissels": { + "account_number": "2851", + "account_type": "Fixed Asset" + }, + "Vastrentende effecten": { + "account_number": "2852", + "account_type": "Fixed Asset" + }, + "Dubieuze debiteuren": { + "account_number": "2857", + "account_type": "Fixed Asset" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2859", + "account_type": "Fixed Asset" + }, + "account_number": "285", + "account_type": "Fixed Asset" + }, + "Borgtochten betaald in contanten": { + "account_number": "288", + "account_type": "Fixed Asset" + }, + "account_number": "28", + "account_type": "Fixed Asset" + }, + "Vorderingen op meer dan 1 jaar": { + "Handelsvorderingen": { + "Handelsdebiteuren": { + "account_number": "2900" + }, + "Te innen wissels": { + "account_number": "2901" + }, + "Vooruitbetalingen": { + "account_number": "2906" + }, + "Dubieuze debiteuren": { + "account_number": "2907" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2909" + }, + "account_number": "290" + }, + "Overige vorderingen": { + "Vorderingen op rekening": { + "account_number": "2910" + }, + "Te innen wissels": { + "account_number": "2911" + }, + "Te ontvangen subsidies": { + "account_number": "2912" + }, + "Niet-rentedragende vorderingen of gekoppeld aan een abnormaal lage rente": { + "account_number": "2915" + }, + "Dubieuze debiteuren": { + "account_number": "2916" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "2919" + }, + "account_number": "291" + }, + "account_number": "29" + } + }, + "KLASSE 3 : VOORRADEN EN BESTELLINGEN IN UITVOERING": { + "root_type": "Asset", + "Grondstoffen": { + "Aanschaffingswaarde": { + "account_number": "300" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "309" + }, + "account_number": "30" + }, + "Hulpstoffen": { + "Aanschaffingswaarde": { + "account_number": "310" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "319" + }, + "account_number": "31" + }, + "Goederen in bewerking": { + "Aanschaffingswaarde": { + "account_number": "320" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "329" + }, + "account_number": "32" + }, + "Gereed product": { + "Aanschaffingswaarde": { + "account_number": "330" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "339" + }, + "account_number": "33" + }, + "Handelsgoederen": { + "Aanschaffingswaarde": { + "account_number": "340", + "account_type": "Stock" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "349" + }, + "account_number": "34", + "account_type": "Stock" + }, + "Onroerende goederen bestemd voor verkoop": { + "Aanschaffingswaarde": { + "account_number": "350" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "359" + }, + "account_number": "35" + }, + "Vooruitbetalingen op voorraadinkopen": { + "Vooruitbetalingen": { + "account_number": "360" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "369" + }, + "account_number": "36" + }, + "Bestellingen in uitvoering": { + "Aanschaffingswaarde": { + "account_number": "370" + }, + "Toegerekende winst": { + "account_number": "371" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "379" + }, + "account_number": "37" + }, + "Geleverde voorraad, niet gefactureerd": { + "account_type": "Stock Delivered But Not Billed" + } + }, + "KLASSE 4 : VORDERINGEN OP TEN HOOGSTE ÉÉN JAAR": { + "root_type": "Asset", + "Handelsvorderingen": { + "Handelsdebiteuren": { + "account_number": "400", + "account_type": "Receivable" + }, + "Te innen wissels": { + "account_number": "401", + "account_type": "Receivable" + }, + "Te innen opbrengsten": { + "account_number": "404", + "account_type": "Receivable" + }, + "Vooruitbetalingen": { + "account_number": "406" + }, + "Dubieuze debiteuren": { + "account_number": "407", + "account_type": "Receivable" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "409" + }, + "account_number": "40", + "account_type": "Receivable" + }, + "Overige vorderingen": { + "Terug te vorderen btw": { + "account_number": "411", + "account_type": "Tax" + }, + "Terug te vorderen belastingen en voorheffingen": { + "Andere Belgische belastingen": { + "account_number": "4125" + }, + "Buitenlandse belastingen": { + "account_number": "4128" + }, + "account_number": "412" + }, + "Te ontvangen subsidies": { + "account_number": "413" + }, + "Te innen opbrengsten": { + "account_number": "414" + }, + "Niet-rentedragende vorderingen of gekoppeld aan een abnormaal lage rente": { + "account_number": "415" + }, + "Diverse vorderingen": { + "account_number": "416" + }, + "Dubieuze debiteuren": { + "account_number": "417" + }, + "Borgtochten betaald in contanten": { + "account_number": "418" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "419" + }, + "account_number": "41" + } + }, + "KLASSE 4 : SCHULDEN OP TEN HOOGSTE ÉÉN JAAR": { + "root_type": "Liability", + "Schulden op meer dan één jaar die binnen het jaar vervallen": { + "account_number": "42" + }, + "Financiële schulden": { + "Kredietinstellingen - Leningen op rekening met vaste termijn": { + "account_number": "430" + }, + "Kredietinstellingen - Promessen": { + "account_number": "431" + }, + "Kredietinstellingen - Acceptkredieten": { + "account_number": "432" + }, + "Kredietinstellingen - Schulden op rekening-courant": { + "account_number": "433" + }, + "Overige leningen": { + "account_number": "439" + }, + "account_number": "43" + }, + "Handelsschulden": { + "Leveranciers": { + "account_number": "440", + "account_type": "Payable" + }, + "Te betalen wissels": { + "account_number": "441", + "account_type": "Payable" + }, + "Te ontvangen facturen": { + "account_number": "444", + "account_type": "Stock Received But Not Billed" + }, + "account_number": "44", + "account_type": "Payable" + }, + "Schulden met betrekking tot belastingen, bezoldigingen en sociale lasten": { + "Geraamd bedrag der belastingschulden": { + "Andere Belgische belastingen": { + "account_number": "4505" + }, + "Buitenlandse belastingen": { + "account_number": "4508" + }, + "account_number": "450" + }, + "Te betalen btw": { + "account_number": "451", + "account_type": "Tax" + }, + "Te betalen belastingen en taksen": { + "Andere Belgische belastingen": { + "account_number": "4525" + }, + "Buitenlandse belastingen": { + "account_number": "4528" + }, + "account_number": "452" + }, + "Ingehouden voorheffingen": { + "account_number": "453" + }, + "Rijksdienst voor Sociale Zekerheid": { + "account_number": "454" + }, + "Bezoldigingen": { + "account_number": "455" + }, + "Vakantiegeld": { + "account_number": "456" + }, + "Andere sociale schulden": { + "account_number": "459" + }, + "account_number": "45" + }, + "Overlopende rekeningen": { + "Over te dragen kosten": { + "account_number": "490" + }, + "Verkregen opbrengsten": { + "account_number": "491" + }, + "Toe te rekenen kosten": { + "account_number": "492" + }, + "Over te dragen opbrengsten": { + "account_number": "493" + }, + "Wachtrekeningen": { + "account_number": "499" + }, + "account_number": "49" + }, + "Vervallen obligaties en coupons": { + "account_number": "480" + }, + "Terug te betalen subsidies": { + "account_number": "483" + }, + "Borgtochten ontvangen in contanten": { + "account_number": "488" + }, + "Andere diverse schulden": { + "Rentedragend": { + "account_number": "4890" + }, + "Niet-rentedragend of gekoppeld aan een abnormaal lage rente": { + "account_number": "4891" + }, + "account_number": "489" + } + }, + "KLASSE 5 : GELDBELEGGINGEN EN LIQUIDE MIDDELEN": { + "root_type": "Asset", + "Geldbeleggingen andere dan aandelen, vastrentende effecten en termijndeposito's": { + "Aanschaffingswaarde": { + "account_number": "500" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "509" + }, + "account_number": "50" + }, + "Aandelen": { + "Aanschaffingswaarde": { + "account_number": "510" + }, + "Nog te storten bedragen (-)": { + "account_number": "511" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "519" + }, + "account_number": "51" + }, + "Vastrentende effecten": { + "Aanschaffingswaarde": { + "account_number": "520" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "529" + }, + "account_number": "52" + }, + "Termijndeposito's": { + "Op meer dan één jaar": { + "account_number": "530" + }, + "Op meer dan één maand en op ten hoogste één jaar": { + "account_number": "531" + }, + "Op ten hoogste één maand": { + "account_number": "532" + }, + "Geboekte waardeverminderingen (-)": { + "account_number": "539" + }, + "account_number": "53" + }, + "Te incasseren vervallen waarden": { + "account_number": "54" + }, + "Kredietinstellingen": { + "Bank": { + "account_number": "5500", + "account_type": "Bank" + }, + "account_number": "55", + "account_type": "Bank" + }, + "Kassen": { + "Kassen-contanten": { + "account_number": "570", + "account_type": "Cash" + }, + "Kassen-zegels": { + "account_number": "578", + "account_type": "Cash" + }, + "account_number": "57", + "account_type": "Cash" + }, + "Interne overboekingen": { + "account_number": "58", + "account_type": "Temporary" + } + }, + "KLASSE 6 : KOSTEN": { + "root_type": "Expense", + "Handelsgoederen, grond- en hulpstoffen": { + "Aankopen van grondstoffen": { + "account_number": "600", + "account_type": "Expense Account" + }, + "Aankopen van hulpstoffen": { + "account_number": "601", + "account_type": "Expense Account" + }, + "Aankopen van diensten, werk en studies": { + "account_number": "602", + "account_type": "Expense Account" + }, + "Algemene onderaannemingen": { + "account_number": "603", + "account_type": "Expense Account" + }, + "Aankopen van handelsgoederen": { + "account_number": "604", + "account_type": "Cost of Goods Sold" + }, + "Aankopen van onroerende goederen bestemd voor verkoop": { + "account_number": "605", + "account_type": "Expense Account" + }, + "Ontvangen kortingen, ristorno's en rabatten (-)": { + "account_number": "608", + "account_type": "Expense Account" + }, + "Voorraadwijzigingen": { + "van grondstoffen": { + "account_number": "6090", + "account_type": "Stock Adjustment" + }, + "van hulpstoffen": { + "account_number": "6091", + "account_type": "Stock Adjustment" + }, + "van handelsgoederen": { + "account_number": "6094", + "account_type": "Stock Adjustment" + }, + "van gekochte onroerende goederen bestemd voor verkoop": { + "account_number": "6095", + "account_type": "Stock Adjustment" + }, + "account_number": "609", + "account_type": "Stock Adjustment" + }, + "account_number": "60", + "account_type": "Expense Account" + }, + "Diensten en diverse goederen": { + "Uitzendpersoneel en personen die ter beschikking worden gesteld van de vereniging of stichting": { + "account_number": "617", + "account_type": "Expense Account" + }, + "Bezoldigingen en pensioenen van bestuurders, buiten arbeidsovereenkomst": { + "account_number": "618", + "account_type": "Expense Account" + }, + "Aankoopkosten begrepen in de waarde van de voorraden": { + "account_type": "Expenses Included In Valuation" + }, + "account_number": "61", + "account_type": "Expense Account" + }, + "Bezoldigingen, sociale lasten en pensioenen": { + "Bezoldigingen en rechtstreekse sociale voordelen": { + "Bestuurders of zaakvoerders": { + "account_number": "6200", + "account_type": "Expense Account" + }, + "Directiepersoneel": { + "account_number": "6201", + "account_type": "Expense Account" + }, + "Bedienden": { + "account_number": "6202", + "account_type": "Expense Account" + }, + "Arbeiders": { + "account_number": "6203", + "account_type": "Expense Account" + }, + "Andere personeelsleden": { + "account_number": "6204", + "account_type": "Expense Account" + }, + "account_number": "620", + "account_type": "Expense Account" + }, + "Werkgeversbijdragen voor sociale verzekeringen": { + "account_number": "621", + "account_type": "Expense Account" + }, + "Werkgeverspremies voor buitenwettelijke verzekeringen": { + "account_number": "622", + "account_type": "Expense Account" + }, + "Andere personeelskosten": { + "account_number": "623", + "account_type": "Expense Account" + }, + "Ouderdoms- en overlevingspensioenen": { + "Bestuurders of zaakvoerders": { + "account_number": "6240", + "account_type": "Expense Account" + }, + "Personeel": { + "account_number": "6241", + "account_type": "Expense Account" + }, + "account_number": "624", + "account_type": "Expense Account" + }, + "account_number": "62", + "account_type": "Expense Account" + }, + "Afschrijvingen, waardeverminderingen en voorzieningen voor risico's en kosten": { + "Afschrijvingen en waardeverminderingen op vaste activa-toevoeging": { + "Afschrijvingen op oprichtingskosten": { + "account_number": "6300", + "account_type": "Depreciation" + }, + "Afschrijvingen op immateriële vaste activa": { + "account_number": "6301", + "account_type": "Depreciation" + }, + "Afschrijvingen op materiële vaste activa": { + "account_number": "6302", + "account_type": "Depreciation" + }, + "Waardeverminderingen op immateriële vaste activa": { + "account_number": "6308", + "account_type": "Depreciation" + }, + "Waardeverminderingen op materiële vaste activa": { + "account_number": "6309", + "account_type": "Depreciation" + }, + "account_number": "630", + "account_type": "Depreciation" + }, + "Waardeverminderingen op voorraden": { + "Toevoeging": { + "account_number": "6310", + "account_type": "Depreciation" + }, + "Terugneming (-)": { + "account_number": "6311", + "account_type": "Depreciation" + }, + "account_number": "631", + "account_type": "Depreciation" + }, + "Waardeverminderingen op bestellingen in uitvoering": { + "Toevoeging": { + "account_number": "6320", + "account_type": "Depreciation" + }, + "Terugneming (-)": { + "account_number": "6321", + "account_type": "Depreciation" + }, + "account_number": "632", + "account_type": "Depreciation" + }, + "Waardeverminderingen op handelsvorderingen op meer dan één jaar": { + "Toevoeging": { + "account_number": "6330", + "account_type": "Depreciation" + }, + "Terugneming (-)": { + "account_number": "6331", + "account_type": "Depreciation" + }, + "account_number": "633", + "account_type": "Depreciation" + }, + "Waardeverminderingen op handelsvorderingen op ten hoogste één jaar": { + "Toevoeging": { + "account_number": "6340", + "account_type": "Depreciation" + }, + "Terugneming (-)": { + "account_number": "6341", + "account_type": "Depreciation" + }, + "account_number": "634", + "account_type": "Depreciation" + }, + "Voorzieningen voor pensioenen en soortgelijke verplichtingen": { + "Toevoeging": { + "account_number": "6350", + "account_type": "Depreciation" + }, + "Besteding en terugneming (-)": { + "account_number": "6351", + "account_type": "Depreciation" + }, + "account_number": "635", + "account_type": "Depreciation" + }, + "Voorzieningen voor grote herstellingswerken en grote onderhoudswerken": { + "Toevoeging": { + "account_number": "6360", + "account_type": "Depreciation" + }, + "Besteding en terugneming (-)": { + "account_number": "6361", + "account_type": "Depreciation" + }, + "account_number": "636", + "account_type": "Depreciation" + }, + "Voorzieningen voor milieuverplichtingen": { + "Toevoeging": { + "account_number": "6370", + "account_type": "Depreciation" + }, + "Besteding en terugneming (-)": { + "account_number": "6371", + "account_type": "Depreciation" + }, + "account_number": "637", + "account_type": "Depreciation" + }, + "Voorzieningen voor terug te betalen subsidies en legaten en voor schenkingen met terugnemingsrecht": { + "Toevoeging": { + "account_number": "6380", + "account_type": "Expense Account" + }, + "Besteding en terugneming (-)": { + "account_number": "6381", + "account_type": "Expense Account" + }, + "account_number": "638", + "account_type": "Expense Account" + }, + "Voorzieningen voor andere risico's en kosten": { + "Toevoeging": { + "account_number": "6390", + "account_type": "Expense Account" + }, + "Besteding en terugneming (-)": { + "account_number": "6391", + "account_type": "Expense Account" + }, + "account_number": "639", + "account_type": "Expense Account" + }, + "account_number": "63", + "account_type": "Expense Account" + }, + "Andere bedrijfskosten": { + "Bedrijfsbelastingen": { + "account_number": "640", + "account_type": "Expense Account" + }, + "Minderwaarden op de courante realisatie van materiële vaste activa": { + "account_number": "641", + "account_type": "Expense Account" + }, + "Minderwaarden op de realisatie van handelsvorderingen": { + "account_number": "642", + "account_type": "Expense Account" + }, + "Schenkingen": { + "account_number": "643", + "account_type": "Expense Account" + }, + "Diverse bedrijfskosten (644 tot 648)": { + "account_number": "644", + "account_type": "Expense Account" + }, + "Als herstructureringskosten geactiveerde bedrijfskosten (-)": { + "account_number": "649", + "account_type": "Expense Account" + }, + "account_number": "64", + "account_type": "Expense Account" + }, + "Financiële kosten": { + "Kosten van schulden": { + "Rente, commissies en kosten verbonden aan schulden": { + "account_number": "6500", + "account_type": "Expense Account" + }, + "Afschrijving van kosten bij uitgifte van leningen en van disagio": { + "account_number": "6501", + "account_type": "Expense Account" + }, + "Geactiveerde intercalaire interesten (-)": { + "account_number": "6502", + "account_type": "Expense Account" + }, + "account_number": "650", + "account_type": "Expense Account" + }, + "Waardeverminderingen op vlottende activa": { + "Toevoeging": { + "account_number": "6510", + "account_type": "Expense Account" + }, + "Terugneming (-)": { + "account_number": "6511", + "account_type": "Expense Account" + }, + "account_number": "651", + "account_type": "Expense Account" + }, + "Minderwaarden op verwezenlijking van vlottende activa": { + "account_number": "652", + "account_type": "Expense Account" + }, + "Discontokosten op vorderingen": { + "account_number": "653", + "account_type": "Expense Account" + }, + "Wisselresultaten": { + "account_number": "654", + "account_type": "Expense Account" + }, + "Resultaten uit de omrekening van vreemde valuta": { + "account_number": "655", + "account_type": "Expense Account" + }, + "Voorzieningen van financiële aard": { + "Toevoeging": { + "account_number": "6560", + "account_type": "Expense Account" + }, + "Besteding en terugneming (-)": { + "account_number": "6561", + "account_type": "Expense Account" + }, + "account_number": "656", + "account_type": "Expense Account" + }, + "Diverse financiële kosten (657 tot 658)": { + "account_number": "657", + "account_type": "Expense Account" + }, + "Als herstructureringskosten geactiveerde financiële kosten (-)": { + "account_number": "659", + "account_type": "Expense Account" + }, + "account_number": "65", + "account_type": "Expense Account" + }, + "Niet-recurrente bedrijfs- of financiële kosten": { + "Niet-recurrente afschrijvingen en waardeverminderingen (toevoeging)": { + "op oprichtingskosten": { + "account_number": "6600", + "account_type": "Expense Account" + }, + "op immateriële vaste activa": { + "account_number": "6601", + "account_type": "Expense Account" + }, + "op materiële vaste activa": { + "account_number": "6602", + "account_type": "Expense Account" + }, + "account_number": "660", + "account_type": "Expense Account" + }, + "Waardeverminderingen op vaste financiële activa (toevoeging)": { + "account_number": "661", + "account_type": "Expense Account" + }, + "Voorzieningen voor niet-recurrente risico's en kosten": { + "Voorzieningen voor niet-recurrente bedrijfsrisico's en -kosten": { + "Toevoeging": { + "account_number": "66200", + "account_type": "Expense Account" + }, + "Bestedingen (-)": { + "account_number": "66201", + "account_type": "Expense Account" + }, + "account_number": "6620", + "account_type": "Expense Account" + }, + "Voorzieningen voor niet-recurrente financiële risico's en -kosten": { + "Toevoeging": { + "account_number": "66210", + "account_type": "Expense Account" + }, + "Besteding (-)": { + "account_number": "66211", + "account_type": "Expense Account" + }, + "account_number": "6621", + "account_type": "Expense Account" + }, + "account_number": "662", + "account_type": "Expense Account" + }, + "Minderwaarden op de realisatie van vaste activa": { + "Minderwaarden op de realisatie van immateriële en materiële vaste activa": { + "account_number": "6630", + "account_type": "Expense Account" + }, + "Minderwaarden op de realisatie van financiële vaste activa": { + "account_number": "6631", + "account_type": "Expense Account" + }, + "account_number": "663", + "account_type": "Expense Account" + }, + "Andere niet-recurrente bedrijfskosten (664 tot 667)": { + "account_number": "664", + "account_type": "Expense Account" + }, + "Andere niet-recurrente financiële kosten": { + "account_number": "668", + "account_type": "Expense Account" + }, + "Als herstructureringskosten geactiveerde niet-recurrente bedrijfskosten (-)": { + "account_number": "6690", + "account_type": "Expense Account" + }, + "Als herstructureringskosten geactiveerde niet-recurrente financiële kosten (-)": { + "account_number": "6691", + "account_type": "Expense Account" + }, + "account_number": "66", + "account_type": "Expense Account" + }, + "Belastingen": { + "Belgische belastingen op het resultaat van het boekjaar": { + "Verschuldigde of gestorte belastingen en voorheffingen": { + "account_number": "6700", + "account_type": "Expense Account" + }, + "Geactiveerde overschotten van betaalde belastingen en voorheffingen (-)": { + "account_number": "6701", + "account_type": "Expense Account" + }, + "Geraamde belastingen": { + "account_number": "6702", + "account_type": "Expense Account" + }, + "account_number": "670", + "account_type": "Expense Account" + }, + "Buitenlandse belastingen op het resultaat van vorige boekjaren": { + "account_number": "673", + "account_type": "Expense Account" + }, + "Verschuldigde of gestorte belastingsupplementen": { + "account_number": "6710", + "account_type": "Expense Account" + }, + "Geraamde belastingsupplementen": { + "account_number": "6711", + "account_type": "Expense Account" + }, + "Gevormde fiscale voorzieningen": { + "account_number": "6712", + "account_type": "Expense Account" + }, + "account_number": "67", + "account_type": "Expense Account" + }, + "Overboeking naar de uitgestelde belastingen en naar de belastingvrije reserves": { + "Overboeking naar de uitgestelde belastingen": { + "account_number": "680", + "account_type": "Expense Account" + }, + "Overboeking naar de belastingvrije reserves": { + "account_number": "689", + "account_type": "Expense Account" + }, + "account_number": "68", + "account_type": "Expense Account" + }, + "Resultaatverwerking": { + "Overgedragen negatief resultaat van het vorig boekjaar": { + "account_number": "690", + "account_type": "Expense Account" + }, + "Overboeking naar de bestemde fondsen en andere reserves": { + "account_number": "691", + "account_type": "Expense Account" + }, + "Over te dragen positief resultaat": { + "account_number": "692", + "account_type": "Expense Account" + }, + "account_number": "69", + "account_type": "Expense Account" + } + }, + "KLASSE 7 : OPBRENGSTEN": { + "root_type": "Income", + "Omzet": { + "Toegekende kortingen, ristorno's en rabatten (-)": { + "account_number": "708", + "account_type": "Income Account" + }, + "account_number": "70", + "account_type": "Income Account" + }, + "Wijziging in de voorraad en bestellingen in uitvoering": { + "In de voorraad goederen in bewerking": { + "account_number": "712", + "account_type": "Income Account" + }, + "In de voorraad gereed product": { + "account_number": "713", + "account_type": "Income Account" + }, + "In de voorraad onroerende goederen bestemd voor verkoop": { + "account_number": "715", + "account_type": "Income Account" + }, + "In de bestellingen in uitvoering": { + "Aanschaffingswaarde": { + "account_number": "7170", + "account_type": "Income Account" + }, + "Toegerekende winst": { + "account_number": "7171", + "account_type": "Income Account" + }, + "account_number": "717", + "account_type": "Income Account" + }, + "account_number": "71", + "account_type": "Income Account" + }, + "Geproduceerde vaste activa": { + "account_number": "72", + "account_type": "Income Account" + }, + "Lidgeld, schenkingen, legaten en subsidies": { + "Lidgelden": { + "account_number": "730", + "account_type": "Income Account" + }, + "Schenkingen": { + "account_number": "731", + "account_type": "Income Account" + }, + "Legaten": { + "account_number": "732", + "account_type": "Income Account" + }, + "Subsidies": { + "account_number": "733", + "account_type": "Income Account" + }, + "account_number": "73", + "account_type": "Income Account" + }, + "Overige bedrijfsopbrengsten": { + "Meerwaarden op de courante realisatie van materiële vaste activa": { + "account_number": "741", + "account_type": "Income Account" + }, + "Meerwaarden op de realisatie van handelsvorderingen": { + "account_number": "742", + "account_type": "Income Account" + }, + "Diverse bedrijfsopbrengsten (743 tot 749)": { + "account_number": "743", + "account_type": "Income Account" + }, + "account_number": "74", + "account_type": "Income Account" + }, + "Financiële opbrengsten": { + "Opbrengsten uit financiële vaste activa": { + "account_number": "750", + "account_type": "Income Account" + }, + "Opbrengsten uit vlottende activa": { + "account_number": "751", + "account_type": "Income Account" + }, + "Meerwaarden op de realisatie van vlottende activa": { + "account_number": "752", + "account_type": "Income Account" + }, + "Wisselresultaten": { + "account_number": "754", + "account_type": "Income Account" + }, + "Resultaten uit de omrekening van vreemde valuta": { + "account_number": "755", + "account_type": "Income Account" + }, + "Diverse financiële opbrengsten (756 tot 759)": { + "account_number": "756", + "account_type": "Income Account" + }, + "account_number": "75", + "account_type": "Income Account" + }, + "Niet-recurrente bedrijfs- of financiële opbrengsten": { + "Terugneming van afschrijvingen en waardeverminderingen": { + "op immateriële vaste activa": { + "account_number": "7600", + "account_type": "Income Account" + }, + "op materiële vaste activa": { + "account_number": "7601", + "account_type": "Income Account" + }, + "account_number": "760", + "account_type": "Income Account" + }, + "Terugneming van waardeverminderingen op financiële vaste activa": { + "account_number": "761", + "account_type": "Income Account" + }, + "Terugneming van voorzieningen voor niet-recurrente risico's en kosten": { + "Terugneming van voorzieningen voor niet-recurrente bedrijfsrisico's en -kosten": { + "account_number": "7620", + "account_type": "Income Account" + }, + "Terugneming van voorzieningen voor niet-recurrente financiële risico's en -kosten": { + "account_number": "7621", + "account_type": "Income Account" + }, + "account_number": "762", + "account_type": "Income Account" + }, + "Meerwaarden op de realisatie van vaste activa": { + "Meerwaarde op de realisatie van immateriële en materiële vaste activa": { + "account_number": "7630", + "account_type": "Income Account" + }, + "Meerwaarde op de realisatie van financiële vaste activa": { + "account_number": "7631", + "account_type": "Income Account" + }, + "account_number": "763", + "account_type": "Income Account" + }, + "Andere niet-recurrente bedrijfsopbrengsten (764 tot 768)": { + "account_number": "764", + "account_type": "Income Account" + }, + "Andere niet-recurrente financiële opbrengsten": { + "account_number": "769", + "account_type": "Income Account" + }, + "account_number": "76", + "account_type": "Income Account" + }, + "Regularisering van belastingen": { + "account_number": "77", + "account_type": "Income Account" + }, + "Onttrekking aan de belastingvrije reserves en uitgestelde belastingen": { + "Onttrekking aan de uitgestelde belastingen": { + "account_number": "780", + "account_type": "Income Account" + }, + "Onttrekking aan de belastingvrije reserves": { + "account_number": "789", + "account_type": "Income Account" + }, + "account_number": "78", + "account_type": "Income Account" + }, + "Resultaatverwerking": { + "Overgedragen positief resultaat van het vorige boekjaar": { + "account_number": "790", + "account_type": "Income Account" + }, + "Andere reserves": { + "account_number": "791", + "account_type": "Income Account" + }, + "Over te dragen negatief resultaat": { + "account_number": "792", + "account_type": "Income Account" + }, + "account_number": "79", + "account_type": "Income Account" + } + } + } +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/be_plan_comptable_minimum_normalise_associations_fondations.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/be_plan_comptable_minimum_normalise_associations_fondations.json new file mode 100644 index 00000000000..5191aa32de9 --- /dev/null +++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/be_plan_comptable_minimum_normalise_associations_fondations.json @@ -0,0 +1,1478 @@ +{ + "country_code": "be", + "name": "Belgique - Plan comptable minimum normalisé (PCMN) des associations et fondations", + "tree": { + "CLASSE 1 : FONDS ASSOCIATIFS ET DE LA FONDATION": { + "root_type": "Equity", + "Fonds de l'association ou de la fondation": { + "account_number": "10", + "account_type": "Equity" + }, + "Plus-values de réévaluation": { + "Plus-values de réévaluation sur immobilisations incorporelles": { + "account_number": "120", + "account_type": "Equity" + }, + "Plus-values de réévaluation sur immobilisations corporelles": { + "account_number": "121", + "account_type": "Equity" + }, + "Plus-values de réévaluation sur immobilisations financières": { + "account_number": "122", + "account_type": "Equity" + }, + "Reprises de réductions de valeur sur placements de trésorerie": { + "account_number": "124", + "account_type": "Equity" + }, + "account_number": "12", + "account_type": "Equity" + }, + "Fonds affectés et autres réserves": { + "Fonds affectés pour investissements": { + "account_number": "130", + "account_type": "Equity" + }, + "Fonds affectés pour passif social": { + "account_number": "131", + "account_type": "Equity" + }, + "Réserves immunisées": { + "account_number": "132", + "account_type": "Equity" + }, + "Autres fonds affectés et autres réserves": { + "account_number": "139", + "account_type": "Equity" + }, + "account_number": "13", + "account_type": "Equity" + }, + "Résultats reportés (+)(-)": { + "account_number": "14", + "account_type": "Equity" + }, + "Subsides en capital": { + "account_number": "15", + "account_type": "Equity" + } + }, + "CLASSE 1 : PROVISIONS ET DETTES À PLUS D'UN AN": { + "root_type": "Liability", + "Provisions et impôts différés": { + "Provisions pour pensions et obligations similaires": { + "account_number": "160", + "account_type": "Liability" + }, + "Provisions pour charges fiscales": { + "account_number": "161", + "account_type": "Liability" + }, + "Provisions pour grosses réparations et gros entretien": { + "account_number": "162", + "account_type": "Liability" + }, + "Provisions pour obligations environnementales": { + "account_number": "163", + "account_type": "Liability" + }, + "Provisions pour remboursement de subsides, legs et dons avec droit de reprise": { + "account_number": "167", + "account_type": "Liability" + }, + "Impôts différés": { + "account_number": "168", + "account_type": "Liability" + }, + "account_number": "16", + "account_type": "Liability" + }, + "Dettes à plus d'un an": { + "Emprunts subordonnés": { + "account_number": "170", + "account_type": "Liability" + }, + "Emprunts obligataires non subordonnés": { + "account_number": "171", + "account_type": "Liability" + }, + "Dettes de location-financement et dettes assimilées": { + "account_number": "172", + "account_type": "Liability" + }, + "Établissements de crédit": { + "Dettes en compte": { + "account_number": "1730", + "account_type": "Liability" + }, + "Promesses": { + "account_number": "1731", + "account_type": "Liability" + }, + "Crédits d'acceptation": { + "account_number": "1732", + "account_type": "Liability" + }, + "account_number": "173", + "account_type": "Liability" + }, + "Autres emprunts": { + "account_number": "174", + "account_type": "Liability" + }, + "Dettes commerciales": { + "Fournisseurs": { + "account_number": "1750", + "account_type": "Liability" + }, + "Effets à payer": { + "account_number": "1751", + "account_type": "Liability" + }, + "account_number": "175", + "account_type": "Liability" + }, + "Acomptes sur commandes": { + "account_number": "176", + "account_type": "Liability" + }, + "Cautionnements en numéraire": { + "account_number": "178", + "account_type": "Liability" + }, + "Autres dettes": { + "Productives d'intérêts": { + "account_number": "1790", + "account_type": "Liability" + }, + "Non productives d'intérêts ou assorties d'un intérêt anormalement faible": { + "account_number": "1791", + "account_type": "Liability" + }, + "account_number": "179", + "account_type": "Liability" + }, + "account_number": "17", + "account_type": "Liability" + } + }, + "CLASSE 2 : FRAIS D'ÉTABLISSEMENT, ACTIFS IMMOBILISÉS ET CRÉANCES À PLUS D'UN AN": { + "root_type": "Asset", + "Frais d'établissement": { + "Frais de constitution": { + "account_number": "200", + "account_type": "Fixed Asset" + }, + "Frais d'émission d'emprunts": { + "account_number": "201", + "account_type": "Fixed Asset" + }, + "Autres frais d'établissement": { + "account_number": "202", + "account_type": "Fixed Asset" + }, + "Frais de restructuration": { + "account_number": "204", + "account_type": "Fixed Asset" + }, + "account_number": "20", + "account_type": "Fixed Asset" + }, + "Immobilisations incorporelles": { + "Frais de recherche et de développement": { + "account_number": "210", + "account_type": "Fixed Asset" + }, + "Concessions, brevets, licences, savoir-faire, marques et droits similaires": { + "account_number": "211", + "account_type": "Fixed Asset" + }, + "Goodwill": { + "account_number": "212", + "account_type": "Fixed Asset" + }, + "Acomptes versés": { + "account_number": "213", + "account_type": "Fixed Asset" + }, + "Amortissements et réductions de valeur actées (-)": { + "account_number": "219", + "account_type": "Accumulated Depreciation" + }, + "account_number": "21", + "account_type": "Fixed Asset" + }, + "Terrains et constructions": { + "Terrains": { + "account_number": "220", + "account_type": "Fixed Asset" + }, + "Constructions": { + "account_number": "221", + "account_type": "Fixed Asset" + }, + "Terrains bâtis": { + "account_number": "222", + "account_type": "Fixed Asset" + }, + "Autres droits réels sur des immeubles": { + "account_number": "223", + "account_type": "Fixed Asset" + }, + "Amortissements et réductions de valeur actées (-)": { + "account_number": "229", + "account_type": "Accumulated Depreciation" + }, + "account_number": "22", + "account_type": "Fixed Asset" + }, + "Installations, machines et outillage": { + "account_number": "23", + "account_type": "Fixed Asset" + }, + "Mobilier et matériel roulant": { + "account_number": "24", + "account_type": "Fixed Asset" + }, + "Immobilisations détenues en location-financement et droits similaires": { + "Terrains et constructions": { + "account_number": "250", + "account_type": "Fixed Asset" + }, + "Installations, machines et outillage": { + "account_number": "251", + "account_type": "Fixed Asset" + }, + "Mobilier et matériel roulant": { + "account_number": "252", + "account_type": "Fixed Asset" + }, + "Amortissements et réductions de valeur actées (-)": { + "account_number": "259", + "account_type": "Accumulated Depreciation" + }, + "account_number": "25", + "account_type": "Fixed Asset" + }, + "Autres immobilisations corporelles": { + "account_number": "26", + "account_type": "Fixed Asset" + }, + "Immobilisations corporelles en cours et acomptes versés": { + "account_number": "27", + "account_type": "Fixed Asset" + }, + "Immobilisations financières": { + "Participations dans des sociétés liées": { + "Valeur d'acquisition": { + "account_number": "2800", + "account_type": "Fixed Asset" + }, + "Montants non appelés (-)": { + "account_number": "2801", + "account_type": "Fixed Asset" + }, + "Plus-values actées": { + "account_number": "2808", + "account_type": "Fixed Asset" + }, + "Réductions de valeur actées (-)": { + "account_number": "2809", + "account_type": "Fixed Asset" + }, + "account_number": "280", + "account_type": "Fixed Asset" + }, + "Créances sur des entités liées": { + "Créances en compte": { + "account_number": "2810", + "account_type": "Fixed Asset" + }, + "Effets à recevoir": { + "account_number": "2811", + "account_type": "Fixed Asset" + }, + "Titres à revenu fixe": { + "account_number": "2812", + "account_type": "Fixed Asset" + }, + "Créances douteuses": { + "account_number": "2817", + "account_type": "Fixed Asset" + }, + "Réductions de valeur actées (-)": { + "account_number": "2819", + "account_type": "Fixed Asset" + }, + "account_number": "281", + "account_type": "Fixed Asset" + }, + "Participations dans des sociétés avec lesquelles il existe un lien de participation": { + "Valeur d'acquisition": { + "account_number": "2820", + "account_type": "Fixed Asset" + }, + "Montants non appelés (-)": { + "account_number": "2821", + "account_type": "Fixed Asset" + }, + "Plus-values actées": { + "account_number": "2828", + "account_type": "Fixed Asset" + }, + "Réductions de valeur actées (-)": { + "account_number": "2829", + "account_type": "Fixed Asset" + }, + "account_number": "282", + "account_type": "Fixed Asset" + }, + "Créances sur des sociétés avec lesquelles il existe un lien de participation": { + "Créances en compte": { + "account_number": "2830", + "account_type": "Fixed Asset" + }, + "Effets à recevoir": { + "account_number": "2831", + "account_type": "Fixed Asset" + }, + "Titres à revenu fixe": { + "account_number": "2832", + "account_type": "Fixed Asset" + }, + "Créances douteuses": { + "account_number": "2837", + "account_type": "Fixed Asset" + }, + "Réductions de valeur actées (-)": { + "account_number": "2839", + "account_type": "Fixed Asset" + }, + "account_number": "283", + "account_type": "Fixed Asset" + }, + "Autres actions et parts": { + "Valeur d'acquisition": { + "account_number": "2840", + "account_type": "Fixed Asset" + }, + "Montants non appelés (-)": { + "account_number": "2841", + "account_type": "Fixed Asset" + }, + "Plus-values actées": { + "account_number": "2848", + "account_type": "Fixed Asset" + }, + "Réductions de valeur actées (-)": { + "account_number": "2849", + "account_type": "Fixed Asset" + }, + "account_number": "284", + "account_type": "Fixed Asset" + }, + "Autres créances": { + "Créances en compte": { + "account_number": "2850", + "account_type": "Fixed Asset" + }, + "Effets à recevoir": { + "account_number": "2851", + "account_type": "Fixed Asset" + }, + "Titres à revenu fixe": { + "account_number": "2852", + "account_type": "Fixed Asset" + }, + "Créances douteuses": { + "account_number": "2857", + "account_type": "Fixed Asset" + }, + "Réductions de valeur actées (-)": { + "account_number": "2859", + "account_type": "Fixed Asset" + }, + "account_number": "285", + "account_type": "Fixed Asset" + }, + "Cautionnements versés en numéraire": { + "account_number": "288", + "account_type": "Fixed Asset" + }, + "account_number": "28", + "account_type": "Fixed Asset" + }, + "Créances à plus d'un an": { + "Créances commerciales": { + "Clients": { + "account_number": "2900" + }, + "Effets à recevoir": { + "account_number": "2901" + }, + "Acomptes versés": { + "account_number": "2906" + }, + "Créances douteuses": { + "account_number": "2907" + }, + "Réductions de valeur actées (-)": { + "account_number": "2909" + }, + "account_number": "290" + }, + "Autres créances": { + "Créances en compte": { + "account_number": "2910" + }, + "Effets à recevoir": { + "account_number": "2911" + }, + "Subsides à recevoir": { + "account_number": "2912" + }, + "Créances non productives d'intérêts ou assorties d'un intérêt anormalement faible": { + "account_number": "2915" + }, + "Créances douteuses": { + "account_number": "2916" + }, + "Réductions de valeur actées (-)": { + "account_number": "2919" + }, + "account_number": "291" + }, + "account_number": "29" + } + }, + "CLASSE 3 : STOCKS ET COMMANDES EN COURS D'EXÉCUTION": { + "root_type": "Asset", + "Matières premières": { + "Valeur d'acquisition": { + "account_number": "300" + }, + "Réductions de valeur actées (-)": { + "account_number": "309" + }, + "account_number": "30" + }, + "Fournitures": { + "Valeur d'acquisition": { + "account_number": "310" + }, + "Réductions de valeur actées (-)": { + "account_number": "319" + }, + "account_number": "31" + }, + "En-cours de fabrication": { + "Valeur d'acquisition": { + "account_number": "320" + }, + "Réductions de valeur actées (-)": { + "account_number": "329" + }, + "account_number": "32" + }, + "Produits finis": { + "Valeur d'acquisition": { + "account_number": "330" + }, + "Réductions de valeur actées (-)": { + "account_number": "339" + }, + "account_number": "33" + }, + "Marchandises": { + "Valeur d'acquisition": { + "account_number": "340", + "account_type": "Stock" + }, + "Réductions de valeur actées (-)": { + "account_number": "349" + }, + "account_number": "34", + "account_type": "Stock" + }, + "Immeubles destinés à la vente": { + "Valeur d'acquisition": { + "account_number": "350" + }, + "Réductions de valeur actées (-)": { + "account_number": "359" + }, + "account_number": "35" + }, + "Acomptes versés sur achats pour stocks": { + "Acomptes versés": { + "account_number": "360" + }, + "Réductions de valeur actées (-)": { + "account_number": "369" + }, + "account_number": "36" + }, + "Commandes en cours d'exécution": { + "Valeur d'acquisition": { + "account_number": "370" + }, + "Bénéfice pris en compte": { + "account_number": "371" + }, + "Réductions de valeur actées (-)": { + "account_number": "379" + }, + "account_number": "37" + }, + "Stock livré non facturé": { + "account_type": "Stock Delivered But Not Billed" + } + }, + "CLASSE 4 : CRÉANCES À UN AN AU PLUS": { + "root_type": "Asset", + "Créances commerciales": { + "Clients": { + "account_number": "400", + "account_type": "Receivable" + }, + "Effets à recevoir": { + "account_number": "401", + "account_type": "Receivable" + }, + "Produits à recevoir": { + "account_number": "404", + "account_type": "Receivable" + }, + "Acomptes versés": { + "account_number": "406" + }, + "Créances douteuses": { + "account_number": "407", + "account_type": "Receivable" + }, + "Réductions de valeur actées (-)": { + "account_number": "409" + }, + "account_number": "40", + "account_type": "Receivable" + }, + "Autres créances": { + "TVA à récupérer": { + "account_number": "411", + "account_type": "Tax" + }, + "Impôts et précomptes à récupérer": { + "Autres impôts et taxes belges (4125 à 4127)": { + "account_number": "4125" + }, + "Impôts et taxes étrangers": { + "account_number": "4128" + }, + "account_number": "412" + }, + "Subsides à recevoir": { + "account_number": "413" + }, + "Produits à recevoir": { + "account_number": "414" + }, + "Créances non productives d'intérêts ou assorties d'un intérêt anormalement faible": { + "account_number": "415" + }, + "Créances diverses": { + "account_number": "416" + }, + "Créances douteuses": { + "account_number": "417" + }, + "Cautionnements versés en numéraire": { + "account_number": "418" + }, + "Réductions de valeur actées (-)": { + "account_number": "419" + }, + "account_number": "41" + } + }, + "CLASSE 4 : DETTES À UN AN AU PLUS": { + "root_type": "Liability", + "Dettes à plus d'un an échéant dans l'année": { + "account_number": "42" + }, + "Dettes financières": { + "Établissements de crédit - Emprunts en compte à terme fixe": { + "account_number": "430" + }, + "Établissements de crédit - Promesses": { + "account_number": "431" + }, + "Établissements de crédit - Crédits d'acceptation": { + "account_number": "432" + }, + "Établissements de crédit - Dettes en compte courant": { + "account_number": "433" + }, + "Autres emprunts": { + "account_number": "439" + }, + "account_number": "43" + }, + "Dettes commerciales": { + "Fournisseurs": { + "account_number": "440", + "account_type": "Payable" + }, + "Effets à payer": { + "account_number": "441", + "account_type": "Payable" + }, + "Factures à recevoir": { + "account_number": "444", + "account_type": "Stock Received But Not Billed" + }, + "account_number": "44", + "account_type": "Payable" + }, + "Dettes fiscales, salariales et sociales": { + "Dettes fiscales estimées": { + "Autres impôts et taxes belges (4505 à 4507)": { + "account_number": "4505" + }, + "Impôts et taxes étrangers": { + "account_number": "4508" + }, + "account_number": "450" + }, + "TVA à payer": { + "account_number": "451", + "account_type": "Tax" + }, + "Impôts et taxes à payer": { + "Autres impôts et taxes belges (4525 à 4527)": { + "account_number": "4525" + }, + "Impôts et taxes étrangers": { + "account_number": "4528" + }, + "account_number": "452" + }, + "Précomptes retenus": { + "account_number": "453" + }, + "Office national de la Sécurité sociale": { + "account_number": "454" + }, + "Rémunérations": { + "account_number": "455" + }, + "Pécules de vacances": { + "account_number": "456" + }, + "Autres dettes sociales": { + "account_number": "459" + }, + "account_number": "45" + }, + "Comptes de régularisation et d'attente": { + "Charges à reporter": { + "account_number": "490" + }, + "Produits acquis": { + "account_number": "491" + }, + "Charges à imputer": { + "account_number": "492" + }, + "Produits à reporter": { + "account_number": "493" + }, + "Comptes d'attente": { + "account_number": "499" + }, + "account_number": "49" + }, + "Obligations et coupons échus": { + "account_number": "480" + }, + "Subsides à rembourser": { + "account_number": "483" + }, + "Cautionnements reçus en numéraire": { + "account_number": "488" + }, + "Autres dettes diverses": { + "Productives d'intérêts": { + "account_number": "4890" + }, + "Non productives d'intérêts ou assorties d'un intérêt anormalement faible": { + "account_number": "4891" + }, + "account_number": "489" + } + }, + "CLASSE 5 : PLACEMENTS DE TRÉSORERIE ET VALEURS DISPONIBLES": { + "root_type": "Asset", + "Placements de trésorerie autres que actions et parts, titres à revenu fixe et dépôts à terme": { + "Valeur d'acquisition": { + "account_number": "500" + }, + "Réductions de valeur actées (-)": { + "account_number": "509" + }, + "account_number": "50" + }, + "Actions et parts": { + "Valeur d'acquisition": { + "account_number": "510" + }, + "Montants non appelés (-)": { + "account_number": "511" + }, + "Réductions de valeur actées (-)": { + "account_number": "519" + }, + "account_number": "51" + }, + "Titres à revenu fixe": { + "Valeur d'acquisition": { + "account_number": "520" + }, + "Réductions de valeur actées (-)": { + "account_number": "529" + }, + "account_number": "52" + }, + "Dépôts à terme": { + "De plus d'un an": { + "account_number": "530" + }, + "De plus d'un mois et à un an au plus": { + "account_number": "531" + }, + "D'un mois au plus": { + "account_number": "532" + }, + "Réductions de valeur actées (-)": { + "account_number": "539" + }, + "account_number": "53" + }, + "Valeurs échues à l'encaissement": { + "account_number": "54" + }, + "Établissements de crédit": { + "Banque": { + "account_number": "5500", + "account_type": "Bank" + }, + "account_number": "55", + "account_type": "Bank" + }, + "Caisses": { + "Caisses-espèces (570 à 577)": { + "account_number": "570", + "account_type": "Cash" + }, + "Caisses-timbres": { + "account_number": "578", + "account_type": "Cash" + }, + "account_number": "57", + "account_type": "Cash" + }, + "Virements internes": { + "account_number": "58", + "account_type": "Temporary" + } + }, + "CLASSE 6 : CHARGES": { + "root_type": "Expense", + "Approvisionnements et marchandises": { + "Achats de matières premières": { + "account_number": "600", + "account_type": "Expense Account" + }, + "Achats de fournitures": { + "account_number": "601", + "account_type": "Expense Account" + }, + "Achats de services, travaux et études": { + "account_number": "602", + "account_type": "Expense Account" + }, + "Sous-traitances générales": { + "account_number": "603", + "account_type": "Expense Account" + }, + "Achats de marchandises": { + "account_number": "604", + "account_type": "Cost of Goods Sold" + }, + "Achats d'immeubles destinés à la vente": { + "account_number": "605", + "account_type": "Expense Account" + }, + "Remises, ristournes et rabais obtenus (-)": { + "account_number": "608", + "account_type": "Expense Account" + }, + "Variations des stocks": { + "de matières premières": { + "account_number": "6090", + "account_type": "Stock Adjustment" + }, + "de fournitures": { + "account_number": "6091", + "account_type": "Stock Adjustment" + }, + "de marchandises": { + "account_number": "6094", + "account_type": "Stock Adjustment" + }, + "d'immeubles destinés à la vente": { + "account_number": "6095", + "account_type": "Stock Adjustment" + }, + "account_number": "609", + "account_type": "Stock Adjustment" + }, + "account_number": "60", + "account_type": "Expense Account" + }, + "Services et biens divers": { + "Personnel intérimaire et personnes mises à la disposition de l'association ou de la fondation": { + "account_number": "617", + "account_type": "Expense Account" + }, + "Rémunérations et pensions des administrateurs, hors contrat de travail": { + "account_number": "618", + "account_type": "Expense Account" + }, + "Frais accessoires d'achat inclus dans la valeur des stocks": { + "account_type": "Expenses Included In Valuation" + }, + "account_number": "61", + "account_type": "Expense Account" + }, + "Rémunérations, charges sociales et pensions": { + "Rémunérations et avantages sociaux directs": { + "Administrateurs ou gérants": { + "account_number": "6200", + "account_type": "Expense Account" + }, + "Personnel de direction": { + "account_number": "6201", + "account_type": "Expense Account" + }, + "Employés": { + "account_number": "6202", + "account_type": "Expense Account" + }, + "Ouvriers": { + "account_number": "6203", + "account_type": "Expense Account" + }, + "Autres membres du personnel": { + "account_number": "6204", + "account_type": "Expense Account" + }, + "account_number": "620", + "account_type": "Expense Account" + }, + "Cotisations patronales pour assurances sociales": { + "account_number": "621", + "account_type": "Expense Account" + }, + "Primes patronales pour assurances extra-légales": { + "account_number": "622", + "account_type": "Expense Account" + }, + "Autres frais du personnel": { + "account_number": "623", + "account_type": "Expense Account" + }, + "Pensions de retraite et de survie": { + "Administrateurs ou gérants": { + "account_number": "6240", + "account_type": "Expense Account" + }, + "Personnel": { + "account_number": "6241", + "account_type": "Expense Account" + }, + "account_number": "624", + "account_type": "Expense Account" + }, + "account_number": "62", + "account_type": "Expense Account" + }, + "Amortissements, réductions de valeur et provisions pour risques et charges": { + "Dotations aux amortissements et aux réductions de valeur sur immobilisations": { + "Dotations aux amortissements sur frais d'établissement": { + "account_number": "6300", + "account_type": "Depreciation" + }, + "Dotation aux amortissements sur immobilisations incorporelles": { + "account_number": "6301", + "account_type": "Depreciation" + }, + "Dotation aux amortissements sur immobilisations corporelles": { + "account_number": "6302", + "account_type": "Depreciation" + }, + "Dotation aux réductions de valeur sur immobilisations incorporelles": { + "account_number": "6308", + "account_type": "Depreciation" + }, + "Dotation aux réductions de valeur sur immobilisations corporelles": { + "account_number": "6309", + "account_type": "Depreciation" + }, + "account_number": "630", + "account_type": "Depreciation" + }, + "Réductions de valeur sur stocks": { + "Dotations": { + "account_number": "6310", + "account_type": "Depreciation" + }, + "Reprises (-)": { + "account_number": "6311", + "account_type": "Depreciation" + }, + "account_number": "631", + "account_type": "Depreciation" + }, + "Réductions de valeur sur commandes en cours d'exécution": { + "Dotations": { + "account_number": "6320", + "account_type": "Depreciation" + }, + "Reprises (-)": { + "account_number": "6321", + "account_type": "Depreciation" + }, + "account_number": "632", + "account_type": "Depreciation" + }, + "Réductions de valeur sur créances commerciales à plus d'un an": { + "Dotations": { + "account_number": "6330", + "account_type": "Depreciation" + }, + "Reprises (-)": { + "account_number": "6331", + "account_type": "Depreciation" + }, + "account_number": "633", + "account_type": "Depreciation" + }, + "Réductions de valeur sur créances à un an au plus": { + "Dotations": { + "account_number": "6340", + "account_type": "Depreciation" + }, + "Reprises (-)": { + "account_number": "6341", + "account_type": "Depreciation" + }, + "account_number": "634", + "account_type": "Depreciation" + }, + "Provisions pour pensions et obligations similaires": { + "Dotations": { + "account_number": "6350", + "account_type": "Depreciation" + }, + "Utilisations et reprises (-)": { + "account_number": "6351", + "account_type": "Depreciation" + }, + "account_number": "635", + "account_type": "Depreciation" + }, + "Provisions pour grosses réparations et gros entretien": { + "Dotations": { + "account_number": "6360", + "account_type": "Depreciation" + }, + "Utilisations et reprises (-)": { + "account_number": "6361", + "account_type": "Depreciation" + }, + "account_number": "636", + "account_type": "Depreciation" + }, + "Provisions pour obligations environnementales": { + "Dotations": { + "account_number": "6370", + "account_type": "Depreciation" + }, + "Utilisations et reprises (-)": { + "account_number": "6371", + "account_type": "Depreciation" + }, + "account_number": "637", + "account_type": "Depreciation" + }, + "Provisions pour subsides et legs à rembourser et pour dons avec droit de reprise": { + "Dotations": { + "account_number": "6380", + "account_type": "Expense Account" + }, + "Utilisations et reprises (-)": { + "account_number": "6381", + "account_type": "Expense Account" + }, + "account_number": "638", + "account_type": "Expense Account" + }, + "Provisions pour autres risques et charges": { + "Dotations": { + "account_number": "6390", + "account_type": "Expense Account" + }, + "Utilisations et reprises (-)": { + "account_number": "6391", + "account_type": "Expense Account" + }, + "account_number": "639", + "account_type": "Expense Account" + }, + "account_number": "63", + "account_type": "Expense Account" + }, + "Autres charges d'exploitation": { + "Charges fiscales": { + "account_number": "640", + "account_type": "Expense Account" + }, + "Moins-values sur réalisations courantes d'immobilisations corporelles": { + "account_number": "641", + "account_type": "Expense Account" + }, + "Moins-values sur réalisations de créances commerciales": { + "account_number": "642", + "account_type": "Expense Account" + }, + "Dons": { + "account_number": "643", + "account_type": "Expense Account" + }, + "Charges d'exploitations diverses (644 à 648)": { + "account_number": "644", + "account_type": "Expense Account" + }, + "Charges d'exploitation portées à l'actif au titre de frais de restructuration (-)": { + "account_number": "649", + "account_type": "Expense Account" + }, + "account_number": "64", + "account_type": "Expense Account" + }, + "Charges financières": { + "Charges des dettes": { + "Intérêts, commissions et frais afférents aux dettes": { + "account_number": "6500", + "account_type": "Expense Account" + }, + "Amortissements frais d'émission d'emprunts et des primes de remboursement": { + "account_number": "6501", + "account_type": "Expense Account" + }, + "Intérêts intercalaires portés à l'actif (-)": { + "account_number": "6502", + "account_type": "Expense Account" + }, + "account_number": "650", + "account_type": "Expense Account" + }, + "Réductions de valeur sur actifs circulants": { + "Dotations": { + "account_number": "6510", + "account_type": "Expense Account" + }, + "Reprises (-)": { + "account_number": "6511", + "account_type": "Expense Account" + }, + "account_number": "651", + "account_type": "Expense Account" + }, + "Moins-values sur réalisation d'actifs circulants": { + "account_number": "652", + "account_type": "Expense Account" + }, + "Charges d'escompte de créances": { + "account_number": "653", + "account_type": "Expense Account" + }, + "Différences de change": { + "account_number": "654", + "account_type": "Expense Account" + }, + "Écarts de conversion des devises": { + "account_number": "655", + "account_type": "Expense Account" + }, + "Provisions à caractère financier": { + "Dotations": { + "account_number": "6560", + "account_type": "Expense Account" + }, + "Utilisations et reprises (-)": { + "account_number": "6561", + "account_type": "Expense Account" + }, + "account_number": "656", + "account_type": "Expense Account" + }, + "Charges financières diverses (657 à 658)": { + "account_number": "657", + "account_type": "Expense Account" + }, + "Charges financières portées à l'actif au titre de frais de restructuration (-)": { + "account_number": "659", + "account_type": "Expense Account" + }, + "account_number": "65", + "account_type": "Expense Account" + }, + "Charges d'exploitation ou financières non récurrentes": { + "Amortissements et réductions de valeur non récurrents (dotations)": { + "sur frais d'établissement": { + "account_number": "6600", + "account_type": "Expense Account" + }, + "sur immobilisations incorporelles": { + "account_number": "6601", + "account_type": "Expense Account" + }, + "sur immobilisations corporelles": { + "account_number": "6602", + "account_type": "Expense Account" + }, + "account_number": "660", + "account_type": "Expense Account" + }, + "Réduction de valeur sur immobilisations financières (dotation)": { + "account_number": "661", + "account_type": "Expense Account" + }, + "Provisions pour risques et charges non récurrents": { + "Provisions pour risques et charges d'exploitation non récurrents": { + "Dotations": { + "account_number": "66200", + "account_type": "Expense Account" + }, + "Utilisations (-)": { + "account_number": "66201", + "account_type": "Expense Account" + }, + "account_number": "6620", + "account_type": "Expense Account" + }, + "Provisions pour risques et charges financiers non récurrents": { + "Dotations": { + "account_number": "66210", + "account_type": "Expense Account" + }, + "Utilisations (-)": { + "account_number": "66211", + "account_type": "Expense Account" + }, + "account_number": "6621", + "account_type": "Expense Account" + }, + "account_number": "662", + "account_type": "Expense Account" + }, + "Moins-values sur réalisation d'actifs immobilisés": { + "Moins-values sur réalisation d'immobilisations incorporelles et corporelles": { + "account_number": "6630", + "account_type": "Expense Account" + }, + "Moins-values sur réalisation d'immobilisations financières": { + "account_number": "6631", + "account_type": "Expense Account" + }, + "account_number": "663", + "account_type": "Expense Account" + }, + "Autres charges d'exploitation non récurrentes (664 à 667)": { + "account_number": "664", + "account_type": "Expense Account" + }, + "Autres charges financières non récurrentes": { + "account_number": "668", + "account_type": "Expense Account" + }, + "Charges d'exploitation portées à l'actif au titre de frais de restructuration (-)": { + "account_number": "6690", + "account_type": "Expense Account" + }, + "Charges financières non récurrentes portées à l'actif au titre de frais de restructuration (-)": { + "account_number": "6691", + "account_type": "Expense Account" + }, + "account_number": "66", + "account_type": "Expense Account" + }, + "Impôts": { + "Impôts belges sur le résultat de l'exercice": { + "Impôts et précomptes dus ou versés": { + "account_number": "6700", + "account_type": "Expense Account" + }, + "Excédent de versements d'impôts et de précomptes porté à l'actif (-)": { + "account_number": "6701", + "account_type": "Expense Account" + }, + "Charges fiscales estimées": { + "account_number": "6702", + "account_type": "Expense Account" + }, + "account_number": "670", + "account_type": "Expense Account" + }, + "Impôts belges sur le résultat d'exercices antérieurs": { + "account_number": "673", + "account_type": "Expense Account" + }, + "Suppléments d'impôts dus ou versés": { + "account_number": "6710", + "account_type": "Expense Account" + }, + "Suppléments d'impôts estimés": { + "account_number": "6711", + "account_type": "Expense Account" + }, + "Provisions fiscales constituées": { + "account_number": "6712", + "account_type": "Expense Account" + }, + "account_number": "67", + "account_type": "Expense Account" + }, + "Transferts aux impôts différés et aux réserves immunisées": { + "Transferts aux impôts différés": { + "account_number": "680", + "account_type": "Expense Account" + }, + "Transferts aux réserves immunisées": { + "account_number": "689", + "account_type": "Expense Account" + }, + "account_number": "68", + "account_type": "Expense Account" + }, + "Affectations et prélèvements": { + "Résultat négatif de l'exercice antérieur reporté": { + "account_number": "690", + "account_type": "Expense Account" + }, + "Transfert aux fonds affectés et autres réserves": { + "account_number": "691", + "account_type": "Expense Account" + }, + "Résultat positif à reporter": { + "account_number": "692", + "account_type": "Expense Account" + }, + "account_number": "69", + "account_type": "Expense Account" + } + }, + "CLASSE 7 : PRODUITS": { + "root_type": "Income", + "Chiffre d'affaires": { + "Remises, ristournes et rabais accordés (-)": { + "account_number": "708", + "account_type": "Income Account" + }, + "account_number": "70", + "account_type": "Income Account" + }, + "Variation des stocks et des commandes en cours d'exécution": { + "Des en-cours de fabrication": { + "account_number": "712", + "account_type": "Income Account" + }, + "Des produits finis": { + "account_number": "713", + "account_type": "Income Account" + }, + "Des immeubles construits destinés à la vente": { + "account_number": "715", + "account_type": "Income Account" + }, + "Des commandes en cours d'exécution": { + "Valeur d'acquisition": { + "account_number": "7170", + "account_type": "Income Account" + }, + "Bénéfice pris en compte": { + "account_number": "7171", + "account_type": "Income Account" + }, + "account_number": "717", + "account_type": "Income Account" + }, + "account_number": "71", + "account_type": "Income Account" + }, + "Production immobilisée": { + "account_number": "72", + "account_type": "Income Account" + }, + "Cotisations, dons, legs et subsides": { + "Cotisations": { + "account_number": "730", + "account_type": "Income Account" + }, + "Dons": { + "account_number": "731", + "account_type": "Income Account" + }, + "Legs": { + "account_number": "732", + "account_type": "Income Account" + }, + "Subsides": { + "account_number": "733", + "account_type": "Income Account" + }, + "account_number": "73", + "account_type": "Income Account" + }, + "Autres produits d'exploitation": { + "Plus-values sur réalisations courantes d'immobilisations corporelles": { + "account_number": "741", + "account_type": "Income Account" + }, + "Plus-values sur réalisation de créances commerciales": { + "account_number": "742", + "account_type": "Income Account" + }, + "Produits d'exploitation divers (743 à 749)": { + "account_number": "743", + "account_type": "Income Account" + }, + "account_number": "74", + "account_type": "Income Account" + }, + "Produits financiers": { + "Produits des immobilisations financières": { + "account_number": "750", + "account_type": "Income Account" + }, + "Produits des actifs circulants": { + "account_number": "751", + "account_type": "Income Account" + }, + "Plus-values sur la réalisation d'actifs circulants": { + "account_number": "752", + "account_type": "Income Account" + }, + "Différences de change": { + "account_number": "754", + "account_type": "Income Account" + }, + "Écarts de conversion des devises": { + "account_number": "755", + "account_type": "Income Account" + }, + "Produits financiers divers (756 à 759)": { + "account_number": "756", + "account_type": "Income Account" + }, + "account_number": "75", + "account_type": "Income Account" + }, + "Produits d'exploitation ou financiers non récurrents": { + "Reprise d'amortissements et réductions de valeur": { + "sur immobilisations incorporelles": { + "account_number": "7600", + "account_type": "Income Account" + }, + "sur immobilisations corporelles": { + "account_number": "7601", + "account_type": "Income Account" + }, + "account_number": "760", + "account_type": "Income Account" + }, + "Reprises de réductions de valeur sur immobilisations financières": { + "account_number": "761", + "account_type": "Income Account" + }, + "Reprises de provisions pour risques et charges non récurrents": { + "Reprises de provisions pour risques et charges d'exploitation non récurrents": { + "account_number": "7620", + "account_type": "Income Account" + }, + "Reprises de provisions pour risques et charges financiers non récurrents": { + "account_number": "7621", + "account_type": "Income Account" + }, + "account_number": "762", + "account_type": "Income Account" + }, + "Plus-values sur réalisation d'actifs immobilisés": { + "Plus-values sur réalisation d'immobilisations incorporelles et corporelles": { + "account_number": "7630", + "account_type": "Income Account" + }, + "Plus-values sur réalisation d'immobilisations financières": { + "account_number": "7631", + "account_type": "Income Account" + }, + "account_number": "763", + "account_type": "Income Account" + }, + "Autres produits d'exploitation non récurrents (764 à 768)": { + "account_number": "764", + "account_type": "Income Account" + }, + "Autres produits financiers non récurrents": { + "account_number": "769", + "account_type": "Income Account" + }, + "account_number": "76", + "account_type": "Income Account" + }, + "Régularisation d'impôts": { + "account_number": "77", + "account_type": "Income Account" + }, + "Prélèvements sur les réserves immunisées et les impôts différés": { + "Prélèvements sur les impôts différés": { + "account_number": "780", + "account_type": "Income Account" + }, + "Prélèvement sur les réserves immunisées": { + "account_number": "789", + "account_type": "Income Account" + }, + "account_number": "78", + "account_type": "Income Account" + }, + "Affectations et prélèvements": { + "Résultat positif de l'exercice antérieur reporté": { + "account_number": "790", + "account_type": "Income Account" + }, + "Autres réserves": { + "account_number": "791", + "account_type": "Income Account" + }, + "Résultat négatif à reporter": { + "account_number": "792", + "account_type": "Income Account" + }, + "account_number": "79", + "account_type": "Income Account" + } + } + } +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/be_plan_comptable_minimum_normalise_entreprises.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/be_plan_comptable_minimum_normalise_entreprises.json new file mode 100644 index 00000000000..2deb46f7300 --- /dev/null +++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/be_plan_comptable_minimum_normalise_entreprises.json @@ -0,0 +1,1597 @@ +{ + "country_code": "be", + "name": "Belgique - Plan comptable minimum normalisé (PCMN) des entreprises", + "tree": { + "CLASSE 1 : CAPITAUX PROPRES": { + "root_type": "Equity", + "Capital": { + "Capital souscrit": { + "account_number": "100", + "account_type": "Equity" + }, + "Capital non appelé (-)": { + "account_number": "101", + "account_type": "Equity" + }, + "account_number": "10", + "account_type": "Equity" + }, + "Apport hors capital": { + "Apport disponible hors capital": { + "Prime d'émission": { + "account_number": "1100", + "account_type": "Equity" + }, + "Autres": { + "account_number": "1109", + "account_type": "Equity" + }, + "account_number": "110", + "account_type": "Equity" + }, + "Apport indisponible hors capital": { + "Prime d'émission": { + "account_number": "1110", + "account_type": "Equity" + }, + "Autres": { + "account_number": "1119", + "account_type": "Equity" + }, + "account_number": "111", + "account_type": "Equity" + }, + "account_number": "11", + "account_type": "Equity" + }, + "Plus-values de réévaluation": { + "Plus-values de réévaluation sur immobilisations incorporelles": { + "account_number": "120", + "account_type": "Equity" + }, + "Plus-values de réévaluation sur immobilisations corporelles": { + "account_number": "121", + "account_type": "Equity" + }, + "Plus-values de réévaluation sur immobilisations financières": { + "account_number": "122", + "account_type": "Equity" + }, + "Plus-values de réévaluation sur stocks": { + "account_number": "123", + "account_type": "Equity" + }, + "Reprises de réductions de valeur sur placements de trésorerie": { + "account_number": "124", + "account_type": "Equity" + }, + "account_number": "12", + "account_type": "Equity" + }, + "Réserves": { + "Réserves légales": { + "account_number": "130", + "account_type": "Equity" + }, + "Autres réserves indisponibles": { + "Réserves statutairement indisponibles": { + "account_number": "1311", + "account_type": "Equity" + }, + "Réserve pour actions propres": { + "account_number": "1312", + "account_type": "Equity" + }, + "Soutien financier": { + "account_number": "1313", + "account_type": "Equity" + }, + "Autres": { + "account_number": "1319", + "account_type": "Equity" + }, + "account_number": "131", + "account_type": "Equity" + }, + "Réserves immunisées": { + "account_number": "132", + "account_type": "Equity" + }, + "Réserves disponibles": { + "account_number": "133", + "account_type": "Equity" + }, + "account_number": "13", + "account_type": "Equity" + }, + "Bénéfice reporté ou perte reportée (-)": { + "account_number": "14", + "account_type": "Equity" + }, + "Subsides en capital": { + "account_number": "15", + "account_type": "Equity" + } + }, + "CLASSE 1 : PROVISIONS ET DETTES À PLUS D'UN AN": { + "root_type": "Liability", + "Provisions et impôts différés": { + "Provisions pour pensions et obligations similaires": { + "account_number": "160", + "account_type": "Liability" + }, + "Provisions pour charges fiscales": { + "account_number": "161", + "account_type": "Liability" + }, + "Provisions pour grosses réparations et gros entretien": { + "account_number": "162", + "account_type": "Liability" + }, + "Provisions pour obligations environnementales": { + "account_number": "163", + "account_type": "Liability" + }, + "Impôts différés": { + "Impôts différés afférents à des subsides en capital": { + "account_number": "1680", + "account_type": "Liability" + }, + "Impôts différés afférents à des plus-values réalisées sur immobilisations incorporelles": { + "account_number": "1681", + "account_type": "Liability" + }, + "Impôts différés afférents à des plus-values réalisées sur immobilisations corporelles": { + "account_number": "1682", + "account_type": "Liability" + }, + "Impôts différés afférents à des plus-values réalisées sur titres émis par le secteur public belge": { + "account_number": "1687", + "account_type": "Liability" + }, + "Impôts différés étrangers": { + "account_number": "1688", + "account_type": "Liability" + }, + "account_number": "168", + "account_type": "Liability" + }, + "account_number": "16", + "account_type": "Liability" + }, + "Dettes à plus d'un an": { + "Emprunts subordonnés": { + "Convertibles": { + "account_number": "1700", + "account_type": "Liability" + }, + "Non convertibles": { + "account_number": "1701", + "account_type": "Liability" + }, + "account_number": "170", + "account_type": "Liability" + }, + "Emprunts obligataires non subordonnés": { + "Convertibles": { + "account_number": "1710", + "account_type": "Liability" + }, + "Non convertibles": { + "account_number": "1711", + "account_type": "Liability" + }, + "account_number": "171", + "account_type": "Liability" + }, + "Dettes de location-financement et assimilées": { + "account_number": "172", + "account_type": "Liability" + }, + "Établissements de crédit": { + "Dettes en compte": { + "account_number": "1730", + "account_type": "Liability" + }, + "Promesses": { + "account_number": "1731", + "account_type": "Liability" + }, + "Crédits d'acceptation": { + "account_number": "1732", + "account_type": "Liability" + }, + "account_number": "173", + "account_type": "Liability" + }, + "Autres emprunts": { + "account_number": "174", + "account_type": "Liability" + }, + "Dettes commerciales": { + "Fournisseurs": { + "account_number": "1750", + "account_type": "Liability" + }, + "Effets à payer": { + "account_number": "1751", + "account_type": "Liability" + }, + "account_number": "175", + "account_type": "Liability" + }, + "Acomptes sur commandes": { + "account_number": "176", + "account_type": "Liability" + }, + "Cautionnements reçus en numéraire": { + "account_number": "178", + "account_type": "Liability" + }, + "Dettes diverses": { + "account_number": "179", + "account_type": "Liability" + }, + "account_number": "17", + "account_type": "Liability" + }, + "Acompte aux associés sur le partage de l'actif net (-)": { + "account_number": "19", + "account_type": "Liability" + } + }, + "CLASSE 2 : FRAIS D'ÉTABLISSEMENT, ACTIFS IMMOBILISÉS ET CRÉANCES À PLUS D'UN AN": { + "root_type": "Asset", + "Frais d'établissement": { + "Frais de constitution, d'augmentation de capital ou d'augmentation de l'apport": { + "account_number": "200", + "account_type": "Fixed Asset" + }, + "Frais d'émission d'emprunts": { + "account_number": "201", + "account_type": "Fixed Asset" + }, + "Autres frais d'établissement": { + "account_number": "202", + "account_type": "Fixed Asset" + }, + "Frais de restructuration": { + "account_number": "204", + "account_type": "Fixed Asset" + }, + "account_number": "20", + "account_type": "Fixed Asset" + }, + "Immobilisations incorporelles": { + "Frais de recherche et de développement": { + "account_number": "210", + "account_type": "Fixed Asset" + }, + "Concessions, brevets, licences, savoir-faire, marques et droits similaires": { + "account_number": "211", + "account_type": "Fixed Asset" + }, + "Goodwill": { + "account_number": "212", + "account_type": "Fixed Asset" + }, + "Acomptes versés": { + "account_number": "213", + "account_type": "Fixed Asset" + }, + "Amortissements et réductions de valeur actées (-)": { + "account_number": "219", + "account_type": "Accumulated Depreciation" + }, + "account_number": "21", + "account_type": "Fixed Asset" + }, + "Terrains et constructions": { + "Terrains": { + "account_number": "220", + "account_type": "Fixed Asset" + }, + "Constructions": { + "account_number": "221", + "account_type": "Fixed Asset" + }, + "Terrains bâtis": { + "account_number": "222", + "account_type": "Fixed Asset" + }, + "Autres droits réels sur des immeubles": { + "account_number": "223", + "account_type": "Fixed Asset" + }, + "Amortissements et réductions de valeur actées (-)": { + "account_number": "229", + "account_type": "Accumulated Depreciation" + }, + "account_number": "22", + "account_type": "Fixed Asset" + }, + "Installations, machines et outillage": { + "account_number": "23", + "account_type": "Fixed Asset" + }, + "Mobilier et matériel roulant": { + "account_number": "24", + "account_type": "Fixed Asset" + }, + "Immobilisations détenues en location-financement et droits similaires": { + "Terrains et constructions": { + "account_number": "250", + "account_type": "Fixed Asset" + }, + "Installations, machines et outillage": { + "account_number": "251", + "account_type": "Fixed Asset" + }, + "Mobilier et matériel roulant": { + "account_number": "252", + "account_type": "Fixed Asset" + }, + "Amortissements et réductions de valeur actées (-)": { + "account_number": "259", + "account_type": "Accumulated Depreciation" + }, + "account_number": "25", + "account_type": "Fixed Asset" + }, + "Autres immobilisations corporelles": { + "account_number": "26", + "account_type": "Fixed Asset" + }, + "Immobilisations corporelles en cours et acomptes versés": { + "account_number": "27", + "account_type": "Fixed Asset" + }, + "Immobilisations financières": { + "Participations dans des entreprises liées": { + "Valeur d'acquisition": { + "account_number": "2800", + "account_type": "Fixed Asset" + }, + "Montants non appelés (-)": { + "account_number": "2801", + "account_type": "Fixed Asset" + }, + "Plus-values actées": { + "account_number": "2808", + "account_type": "Fixed Asset" + }, + "Réductions de valeur actées (-)": { + "account_number": "2809", + "account_type": "Fixed Asset" + }, + "account_number": "280", + "account_type": "Fixed Asset" + }, + "Créances sur des entreprises liées": { + "Créances en compte": { + "account_number": "2810", + "account_type": "Fixed Asset" + }, + "Effets à recevoir": { + "account_number": "2811", + "account_type": "Fixed Asset" + }, + "Titres à revenu fixe": { + "account_number": "2812", + "account_type": "Fixed Asset" + }, + "Créances douteuses": { + "account_number": "2817", + "account_type": "Fixed Asset" + }, + "Réductions de valeur actées (-)": { + "account_number": "2819", + "account_type": "Fixed Asset" + }, + "account_number": "281", + "account_type": "Fixed Asset" + }, + "Participations dans des entreprises avec lesquelles il existe un lien de participation": { + "Valeur d'acquisition": { + "account_number": "2820", + "account_type": "Fixed Asset" + }, + "Montants non appelés (-)": { + "account_number": "2821", + "account_type": "Fixed Asset" + }, + "Plus-values actées": { + "account_number": "2828", + "account_type": "Fixed Asset" + }, + "Réductions de valeur actées (-)": { + "account_number": "2829", + "account_type": "Fixed Asset" + }, + "account_number": "282", + "account_type": "Fixed Asset" + }, + "Créances sur des entreprises avec lesquelles il existe un lien de participation": { + "Créances en compte": { + "account_number": "2830", + "account_type": "Fixed Asset" + }, + "Effets à recevoir": { + "account_number": "2831", + "account_type": "Fixed Asset" + }, + "Titres à revenu fixe": { + "account_number": "2832", + "account_type": "Fixed Asset" + }, + "Créances douteuses": { + "account_number": "2837", + "account_type": "Fixed Asset" + }, + "Réductions de valeur actées (-)": { + "account_number": "2839", + "account_type": "Fixed Asset" + }, + "account_number": "283", + "account_type": "Fixed Asset" + }, + "Autres actions et parts": { + "Valeur d'acquisition": { + "account_number": "2840", + "account_type": "Fixed Asset" + }, + "Montants non appelés (-)": { + "account_number": "2841", + "account_type": "Fixed Asset" + }, + "Plus-values actées": { + "account_number": "2848", + "account_type": "Fixed Asset" + }, + "Réductions de valeur actées (-)": { + "account_number": "2849", + "account_type": "Fixed Asset" + }, + "account_number": "284", + "account_type": "Fixed Asset" + }, + "Autres créances": { + "Créances en compte": { + "account_number": "2850", + "account_type": "Fixed Asset" + }, + "Effets à recevoir": { + "account_number": "2851", + "account_type": "Fixed Asset" + }, + "Titres à revenu fixe": { + "account_number": "2852", + "account_type": "Fixed Asset" + }, + "Créances douteuses": { + "account_number": "2857", + "account_type": "Fixed Asset" + }, + "Réductions de valeur actées (-)": { + "account_number": "2859", + "account_type": "Fixed Asset" + }, + "account_number": "285", + "account_type": "Fixed Asset" + }, + "Cautionnements versés en numéraire": { + "account_number": "288", + "account_type": "Fixed Asset" + }, + "account_number": "28", + "account_type": "Fixed Asset" + }, + "Créances à plus d'un an": { + "Créances commerciales": { + "Clients": { + "account_number": "2900" + }, + "Effets à recevoir": { + "account_number": "2901" + }, + "Acomptes versés": { + "account_number": "2906" + }, + "Créances douteuses": { + "account_number": "2907" + }, + "Réductions de valeur actées (-)": { + "account_number": "2909" + }, + "account_number": "290" + }, + "Autres créances": { + "Créances en compte": { + "account_number": "2910" + }, + "Effets à recevoir": { + "account_number": "2911" + }, + "Créances douteuses": { + "account_number": "2917" + }, + "Réductions de valeur actées (-)": { + "account_number": "2919" + }, + "account_number": "291" + }, + "account_number": "29" + } + }, + "CLASSE 3 : STOCKS ET COMMANDES EN COURS D'EXÉCUTION": { + "root_type": "Asset", + "Matières premières": { + "Valeur d'acquisition": { + "account_number": "300" + }, + "Réductions de valeur actées (-)": { + "account_number": "309" + }, + "account_number": "30" + }, + "Approvisionnements et fournitures": { + "Valeur d'acquisition": { + "account_number": "310" + }, + "Réductions de valeur actées (-)": { + "account_number": "319" + }, + "account_number": "31" + }, + "En-cours de fabrication": { + "Valeur d'acquisition": { + "account_number": "320" + }, + "Réductions de valeur actées (-)": { + "account_number": "329" + }, + "account_number": "32" + }, + "Produits finis": { + "Valeur d'acquisition": { + "account_number": "330" + }, + "Réductions de valeur actées (-)": { + "account_number": "339" + }, + "account_number": "33" + }, + "Marchandises": { + "Valeur d'acquisition": { + "account_number": "340", + "account_type": "Stock" + }, + "Réductions de valeur actées (-)": { + "account_number": "349" + }, + "account_number": "34", + "account_type": "Stock" + }, + "Immeubles destinés à la vente": { + "Valeur d'acquisition": { + "account_number": "350" + }, + "Réductions de valeur actées (-)": { + "account_number": "359" + }, + "account_number": "35" + }, + "Acomptes versés sur achats pour stocks": { + "Acomptes versés": { + "account_number": "360" + }, + "Réductions de valeur actées (-)": { + "account_number": "369" + }, + "account_number": "36" + }, + "Commandes en cours d'exécution": { + "Valeur d'acquisition": { + "account_number": "370" + }, + "Bénéfice pris en compte": { + "account_number": "371" + }, + "Réductions de valeur actées (-)": { + "account_number": "379" + }, + "account_number": "37" + }, + "Stock livré non facturé": { + "account_type": "Stock Delivered But Not Billed" + } + }, + "CLASSE 4 : CRÉANCES À UN AN AU PLUS": { + "root_type": "Asset", + "Créances commerciales": { + "Clients": { + "account_number": "400", + "account_type": "Receivable" + }, + "Effets à recevoir": { + "account_number": "401", + "account_type": "Receivable" + }, + "Produits à recevoir": { + "account_number": "404", + "account_type": "Receivable" + }, + "Acomptes versés": { + "account_number": "406" + }, + "Créances douteuses": { + "account_number": "407", + "account_type": "Receivable" + }, + "Réductions de valeur actées (-)": { + "account_number": "409" + }, + "account_number": "40", + "account_type": "Receivable" + }, + "Autres créances": { + "Capital ou apport appelé, non versé": { + "account_number": "410" + }, + "TVA à récupérer": { + "account_number": "411", + "account_type": "Tax" + }, + "Impôts et précomptes à récupérer": { + "Impôts et taxes étrangers": { + "account_number": "4128" + }, + "account_number": "412" + }, + "Produits à recevoir": { + "account_number": "414" + }, + "Créances diverses": { + "account_number": "416" + }, + "Créances douteuses": { + "account_number": "417" + }, + "Cautionnements versés en numéraire": { + "account_number": "418" + }, + "Réductions de valeur actées (-)": { + "account_number": "419" + }, + "account_number": "41" + } + }, + "CLASSE 4 : DETTES À UN AN AU PLUS": { + "root_type": "Liability", + "Dettes à plus d'un an échéant dans l'année (16) (même subdivision que le compte 17)": { + "account_number": "42" + }, + "Dettes financières": { + "Établissements de crédit - Emprunts en compte à terme fixe": { + "account_number": "430" + }, + "Établissements de crédit - Promesses": { + "account_number": "431" + }, + "Établissements de crédit - Crédits d'acceptation": { + "account_number": "432" + }, + "Établissements de crédit - Dettes en compte courant": { + "account_number": "433" + }, + "Autres emprunts": { + "account_number": "439" + }, + "account_number": "43" + }, + "Dettes commerciales": { + "Fournisseurs": { + "account_number": "440", + "account_type": "Payable" + }, + "Effets à payer": { + "account_number": "441", + "account_type": "Payable" + }, + "Factures à recevoir": { + "account_number": "444", + "account_type": "Stock Received But Not Billed" + }, + "account_number": "44", + "account_type": "Payable" + }, + "Dettes fiscales, salariales et sociales": { + "Dettes fiscales estimées": { + "Impôts et taxes étrangers": { + "account_number": "4508" + }, + "account_number": "450" + }, + "TVA à payer": { + "account_number": "451", + "account_type": "Tax" + }, + "Impôts et taxes à payer": { + "Impôts et taxes étrangers": { + "account_number": "4528" + }, + "account_number": "452" + }, + "Précomptes retenus": { + "account_number": "453" + }, + "Office national de la Sécurité sociale": { + "account_number": "454" + }, + "Rémunérations": { + "account_number": "455" + }, + "Pécules de vacances": { + "account_number": "456" + }, + "Autres dettes sociales": { + "account_number": "459" + }, + "account_number": "45" + }, + "Acomptes sur commandes": { + "account_number": "46" + }, + "Dettes découlant de l'affectation du résultat": { + "Dividendes et tantièmes d'exercices antérieurs": { + "account_number": "470" + }, + "Dividendes de l'exercice": { + "account_number": "471" + }, + "Tantièmes de l'exercice": { + "account_number": "472" + }, + "Autres allocataires": { + "account_number": "473" + }, + "account_number": "47" + }, + "Dettes diverses": { + "Obligations et coupons échus": { + "account_number": "480" + }, + "Cautionnements reçus en numéraire": { + "account_number": "488" + }, + "Autres dettes diverses": { + "account_number": "489" + }, + "account_number": "48" + }, + "Comptes de régularisation et d'attente": { + "Charges à reporter": { + "account_number": "490" + }, + "Produits acquis": { + "account_number": "491" + }, + "Charges à imputer": { + "account_number": "492" + }, + "Produits à reporter": { + "account_number": "493" + }, + "Comptes d'attente": { + "account_number": "499" + }, + "account_number": "49" + } + }, + "CLASSE 5 : PLACEMENTS DE TRÉSORERIE ET VALEURS DISPONIBLES": { + "root_type": "Asset", + "Actions propres": { + "account_number": "50" + }, + "Actions, parts et placements de trésorerie autres que placements à revenu fixe": { + "Valeur d'acquisition": { + "Actions et parts": { + "account_number": "5100" + }, + "Placements de trésorerie autres que placements à revenu fixe": { + "account_number": "5101" + }, + "account_number": "510" + }, + "Montants non appelés (-)": { + "Actions et parts": { + "account_number": "5110" + }, + "account_number": "511" + }, + "Réductions de valeur actées (-)": { + "Actions et parts": { + "account_number": "5190" + }, + "Placements de trésorerie autres que placements à revenu fixe": { + "account_number": "5191" + }, + "account_number": "519" + }, + "account_number": "51" + }, + "Titres à revenu fixe": { + "Valeur d'acquisition": { + "account_number": "520" + }, + "Réductions de valeur actées (-)": { + "account_number": "529" + }, + "account_number": "52" + }, + "Dépôts à terme": { + "De plus d'un an": { + "account_number": "530" + }, + "De plus d'un mois et à un an au plus": { + "account_number": "531" + }, + "D'un mois au plus": { + "account_number": "532" + }, + "Réductions de valeur actées (-)": { + "account_number": "539" + }, + "account_number": "53" + }, + "Valeurs échues à l'encaissement": { + "account_number": "54" + }, + "Établissements de crédit": { + "Banque": { + "account_number": "5500", + "account_type": "Bank" + }, + "account_number": "55", + "account_type": "Bank" + }, + "Caisses": { + "Caisses-timbres": { + "account_number": "578", + "account_type": "Cash" + }, + "account_number": "57", + "account_type": "Cash" + }, + "Virements internes": { + "account_number": "58", + "account_type": "Temporary" + } + }, + "CLASSE 6 : CHARGES": { + "root_type": "Expense", + "Approvisionnements et marchandises": { + "Achats de matières premières": { + "account_number": "600", + "account_type": "Expense Account" + }, + "Achats de fournitures": { + "account_number": "601", + "account_type": "Expense Account" + }, + "Achats de services, travaux et études": { + "account_number": "602", + "account_type": "Expense Account" + }, + "Sous-traitances générales": { + "account_number": "603", + "account_type": "Expense Account" + }, + "Achats de marchandises": { + "account_number": "604", + "account_type": "Cost of Goods Sold" + }, + "Achats d'immeubles destinés à la vente": { + "account_number": "605", + "account_type": "Expense Account" + }, + "Remises, ristournes et rabais (-)": { + "account_number": "608", + "account_type": "Expense Account" + }, + "Variations des stocks": { + "de matières premières": { + "account_number": "6090", + "account_type": "Stock Adjustment" + }, + "de fournitures": { + "account_number": "6091", + "account_type": "Stock Adjustment" + }, + "de marchandises": { + "account_number": "6094", + "account_type": "Stock Adjustment" + }, + "d'immeubles achetés destinés à la vente": { + "account_number": "6095", + "account_type": "Stock Adjustment" + }, + "account_number": "609", + "account_type": "Stock Adjustment" + }, + "account_number": "60", + "account_type": "Expense Account" + }, + "Services et biens divers": { + "Personnel intérimaire et personnes mises à la disposition de l'entreprise": { + "account_number": "617", + "account_type": "Expense Account" + }, + "Rémunérations et pensions des administrateurs, gérants et associés actifs, hors contrat de travail": { + "account_number": "618", + "account_type": "Expense Account" + }, + "Frais accessoires d'achat inclus dans la valeur des stocks": { + "account_type": "Expenses Included In Valuation" + }, + "account_number": "61", + "account_type": "Expense Account" + }, + "Rémunérations, charges sociales et pensions": { + "Rémunérations et avantages sociaux directs": { + "Administrateurs ou gérants": { + "account_number": "6200", + "account_type": "Expense Account" + }, + "Personnel de direction": { + "account_number": "6201", + "account_type": "Expense Account" + }, + "Employés": { + "account_number": "6202", + "account_type": "Expense Account" + }, + "Ouvriers": { + "account_number": "6203", + "account_type": "Expense Account" + }, + "Autres membres du personnel": { + "account_number": "6204", + "account_type": "Expense Account" + }, + "account_number": "620", + "account_type": "Expense Account" + }, + "Cotisations patronales pour assurances sociales": { + "account_number": "621", + "account_type": "Expense Account" + }, + "Primes patronales pour assurances extra-légales": { + "account_number": "622", + "account_type": "Expense Account" + }, + "Autres frais du personnel": { + "account_number": "623", + "account_type": "Expense Account" + }, + "Pensions de retraite et de survie": { + "Administrateurs ou gérants": { + "account_number": "6240", + "account_type": "Expense Account" + }, + "Personnel": { + "account_number": "6241", + "account_type": "Expense Account" + }, + "account_number": "624", + "account_type": "Expense Account" + }, + "account_number": "62", + "account_type": "Expense Account" + }, + "Amortissements, réductions de valeur et provisions pour risques": { + "Dotations aux amortissements et aux réductions de valeur sur immobilisations": { + "Dotations aux amortissements sur frais d'établissement": { + "account_number": "6300", + "account_type": "Depreciation" + }, + "Dotation aux amortissements sur immobilisations incorporelles": { + "account_number": "6301", + "account_type": "Depreciation" + }, + "Dotation aux amortissements sur immobilisations corporelles": { + "account_number": "6302", + "account_type": "Depreciation" + }, + "Dotation aux réductions de valeur sur immobilisations incorporelles": { + "account_number": "6308", + "account_type": "Depreciation" + }, + "Dotation aux réductions de valeur sur immobilisations corporelles": { + "account_number": "6309", + "account_type": "Depreciation" + }, + "account_number": "630", + "account_type": "Depreciation" + }, + "Réductions de valeur sur stocks": { + "Dotations": { + "account_number": "6310", + "account_type": "Depreciation" + }, + "Reprises (-)": { + "account_number": "6311", + "account_type": "Depreciation" + }, + "account_number": "631", + "account_type": "Depreciation" + }, + "Réductions de valeur sur commandes en cours d'exécution": { + "Dotations": { + "account_number": "6320", + "account_type": "Depreciation" + }, + "Reprises (-)": { + "account_number": "6321", + "account_type": "Depreciation" + }, + "account_number": "632", + "account_type": "Depreciation" + }, + "Réductions de valeur sur créances commerciales à plus d'un an": { + "Dotations": { + "account_number": "6330", + "account_type": "Depreciation" + }, + "Reprises (-)": { + "account_number": "6331", + "account_type": "Depreciation" + }, + "account_number": "633", + "account_type": "Depreciation" + }, + "Réductions de valeur sur créances à un an au plus": { + "Dotations": { + "account_number": "6340", + "account_type": "Depreciation" + }, + "Reprises (-)": { + "account_number": "6341", + "account_type": "Depreciation" + }, + "account_number": "634", + "account_type": "Depreciation" + }, + "Provisions pour pensions et obligations similaires": { + "Dotations": { + "account_number": "6350", + "account_type": "Depreciation" + }, + "Utilisations et reprises (-)": { + "account_number": "6351", + "account_type": "Depreciation" + }, + "account_number": "635", + "account_type": "Depreciation" + }, + "Provisions pour grosses réparations et gros entretien": { + "Dotations": { + "account_number": "6360", + "account_type": "Depreciation" + }, + "Utilisations et reprises (-)": { + "account_number": "6361", + "account_type": "Depreciation" + }, + "account_number": "636", + "account_type": "Depreciation" + }, + "Provisions pour obligations environnementales": { + "Dotations": { + "account_number": "6370", + "account_type": "Depreciation" + }, + "Utilisations et reprises (-)": { + "account_number": "6371", + "account_type": "Depreciation" + }, + "account_number": "637", + "account_type": "Depreciation" + }, + "Provisions pour autres risques et charges": { + "Dotations": { + "account_number": "6380", + "account_type": "Expense Account" + }, + "Utilisations et reprises (-)": { + "account_number": "6381", + "account_type": "Expense Account" + }, + "account_number": "638", + "account_type": "Expense Account" + }, + "account_number": "63", + "account_type": "Expense Account" + }, + "Autres charges d'exploitation": { + "Charges fiscales d'exploitation": { + "account_number": "640", + "account_type": "Expense Account" + }, + "Moins-values sur réalisations courantes d'immobilisations corporelles": { + "account_number": "641", + "account_type": "Expense Account" + }, + "Moins-values sur réalisations de créances commerciales": { + "account_number": "642", + "account_type": "Expense Account" + }, + "Charges d'exploitations diverses (643 à 648)": { + "account_number": "643", + "account_type": "Expense Account" + }, + "Charges d'exploitation portées à l'actif au titre de frais de restructuration (-)": { + "account_number": "649", + "account_type": "Expense Account" + }, + "account_number": "64", + "account_type": "Expense Account" + }, + "Charges financières": { + "Charges des dettes": { + "Intérêts, commissions et frais afférents aux dettes": { + "account_number": "6500", + "account_type": "Expense Account" + }, + "Amortissements des frais d'émission d'emprunts": { + "account_number": "6501", + "account_type": "Expense Account" + }, + "Intérêts intercalaires portés à l'actif (-)": { + "account_number": "6502", + "account_type": "Expense Account" + }, + "account_number": "650", + "account_type": "Expense Account" + }, + "Réductions de valeur sur actifs circulants": { + "Dotations": { + "account_number": "6510", + "account_type": "Expense Account" + }, + "Reprises (-)": { + "account_number": "6511", + "account_type": "Expense Account" + }, + "account_number": "651", + "account_type": "Expense Account" + }, + "Moins-values sur réalisation d'actifs circulants": { + "account_number": "652", + "account_type": "Expense Account" + }, + "Charges d'escompte de créances": { + "account_number": "653", + "account_type": "Expense Account" + }, + "Différences de change": { + "account_number": "654", + "account_type": "Expense Account" + }, + "Écarts de conversion des devises": { + "account_number": "655", + "account_type": "Expense Account" + }, + "Provisions à caractère financier": { + "Dotations": { + "account_number": "6560", + "account_type": "Expense Account" + }, + "Utilisations et reprises (-)": { + "account_number": "6561", + "account_type": "Expense Account" + }, + "account_number": "656", + "account_type": "Expense Account" + }, + "Charges financières diverses (657 à 658)": { + "account_number": "657", + "account_type": "Expense Account" + }, + "Charges financières portées à l'actif au titre de frais de restructuration (-)": { + "account_number": "659", + "account_type": "Expense Account" + }, + "account_number": "65", + "account_type": "Expense Account" + }, + "Charges d'exploitation et charges financières non récurrentes": { + "Amortissements et réductions de valeur non récurrents (dotations)": { + "sur frais d'établissement": { + "account_number": "6600", + "account_type": "Expense Account" + }, + "sur immobilisations incorporelles": { + "account_number": "6601", + "account_type": "Expense Account" + }, + "sur immobilisations corporelles": { + "account_number": "6602", + "account_type": "Expense Account" + }, + "account_number": "660", + "account_type": "Expense Account" + }, + "Réduction de valeur sur immobilisations financières (dotation)": { + "account_number": "661", + "account_type": "Expense Account" + }, + "Provisions pour risques et charges non récurrents": { + "Provisions pour risques et charges d'exploitation non récurrents": { + "Dotations": { + "account_number": "66200", + "account_type": "Expense Account" + }, + "Utilisations (-)": { + "account_number": "66201", + "account_type": "Expense Account" + }, + "account_number": "6620", + "account_type": "Expense Account" + }, + "Provisions pour risques et charges financiers non récurrents": { + "Dotations": { + "account_number": "66210", + "account_type": "Expense Account" + }, + "Utilisations (-)": { + "account_number": "66211", + "account_type": "Expense Account" + }, + "account_number": "6621", + "account_type": "Expense Account" + }, + "account_number": "662", + "account_type": "Expense Account" + }, + "Moins-values sur réalisation d'actifs immobilisés": { + "Moins-values sur réalisation d'immobilisations incorporelles et corporelles": { + "account_number": "6630", + "account_type": "Expense Account" + }, + "Moins-values sur réalisation d'immobilisations financières": { + "account_number": "6631", + "account_type": "Expense Account" + }, + "account_number": "663", + "account_type": "Expense Account" + }, + "Autres charges d'exploitation non récurrentes (664 à 667)": { + "account_number": "664", + "account_type": "Expense Account" + }, + "Autres charges financières non récurrentes": { + "account_number": "668", + "account_type": "Expense Account" + }, + "Charges d'exploitation non récurrentes portées à l'actif au titre de frais de restructuration (-)": { + "account_number": "6690", + "account_type": "Expense Account" + }, + "Charges financières non récurrentes portées à l'actif au titre de frais de restructuration (-)": { + "account_number": "6691", + "account_type": "Expense Account" + }, + "account_number": "66", + "account_type": "Expense Account" + }, + "Impôts sur le résultat": { + "Impôts belges sur le résultat de l'exercice": { + "Impôts et précomptes dus ou versés": { + "account_number": "6700", + "account_type": "Expense Account" + }, + "Excédent de versements d'impôts et de précomptes porté à l'actif (-)": { + "account_number": "6701", + "account_type": "Expense Account" + }, + "Charges fiscales estimées": { + "account_number": "6702", + "account_type": "Expense Account" + }, + "account_number": "670", + "account_type": "Expense Account" + }, + "Impôts belges sur le résultat d'exercices antérieurs": { + "Suppléments d'impôts dus ou versés": { + "account_number": "6710", + "account_type": "Expense Account" + }, + "Suppléments d'impôts estimés": { + "account_number": "6711", + "account_type": "Expense Account" + }, + "Provisions fiscales constituées": { + "account_number": "6712", + "account_type": "Expense Account" + }, + "account_number": "671", + "account_type": "Expense Account" + }, + "Impôts étrangers sur le résultat de l'exercice": { + "account_number": "672", + "account_type": "Expense Account" + }, + "Impôts étrangers sur le résultat d'exercices antérieurs": { + "account_number": "673", + "account_type": "Expense Account" + }, + "account_number": "67", + "account_type": "Expense Account" + }, + "Transferts aux impôts différés et aux réserves immunisées": { + "Transferts aux impôts différés": { + "account_number": "680", + "account_type": "Expense Account" + }, + "Transferts aux réserves immunisées": { + "account_number": "689", + "account_type": "Expense Account" + }, + "account_number": "68", + "account_type": "Expense Account" + }, + "Affectations et prélèvements": { + "Perte reportée de l'exercice précédent": { + "account_number": "690", + "account_type": "Expense Account" + }, + "Affectations à l'apport": { + "account_number": "691", + "account_type": "Expense Account" + }, + "Dotation aux réserves": { + "Dotation à la réserve légale": { + "account_number": "6920", + "account_type": "Expense Account" + }, + "Dotation aux autres réserves": { + "account_number": "6921", + "account_type": "Expense Account" + }, + "account_number": "692", + "account_type": "Expense Account" + }, + "Bénéfices à reporter": { + "account_number": "693", + "account_type": "Expense Account" + }, + "Rémunération de l'apport": { + "account_number": "694", + "account_type": "Expense Account" + }, + "Administrateurs ou gérants": { + "account_number": "695", + "account_type": "Expense Account" + }, + "Employés": { + "account_number": "696", + "account_type": "Expense Account" + }, + "Autres applications": { + "account_number": "697", + "account_type": "Expense Account" + }, + "account_number": "69", + "account_type": "Expense Account" + } + }, + "CLASSE 7 : PRODUITS": { + "root_type": "Income", + "Chiffre d'affaires": { + "Remises, ristournes et rabais accordés (-)": { + "account_number": "708", + "account_type": "Income Account" + }, + "account_number": "70", + "account_type": "Income Account" + }, + "Variation des stocks et des commandes en cours d'exécution": { + "Des en-cours de fabrication": { + "account_number": "712", + "account_type": "Income Account" + }, + "Des produits finis": { + "account_number": "713", + "account_type": "Income Account" + }, + "Des immeubles construits destinés à la vente": { + "account_number": "715", + "account_type": "Income Account" + }, + "Des commandes en cours d'exécution": { + "Valeur d'acquisition": { + "account_number": "7170", + "account_type": "Income Account" + }, + "Bénéfice pris en compte": { + "account_number": "7171", + "account_type": "Income Account" + }, + "account_number": "717", + "account_type": "Income Account" + }, + "account_number": "71", + "account_type": "Income Account" + }, + "Production immobilisée": { + "account_number": "72", + "account_type": "Income Account" + }, + "Autres produits d'exploitation": { + "Subsides d'exploitation et montants compensatoires": { + "account_number": "740", + "account_type": "Income Account" + }, + "Plus-values sur réalisations courantes d'immobilisations corporelles": { + "account_number": "741", + "account_type": "Income Account" + }, + "Plus-values sur réalisation de créances commerciales": { + "account_number": "742", + "account_type": "Income Account" + }, + "Produits d'exploitation divers (743 à 749)": { + "account_number": "743", + "account_type": "Income Account" + }, + "account_number": "74", + "account_type": "Income Account" + }, + "Produits financiers": { + "Produits des immobilisations financières": { + "account_number": "750", + "account_type": "Income Account" + }, + "Produits des actifs circulants": { + "account_number": "751", + "account_type": "Income Account" + }, + "Plus-values sur réalisation d'actifs circulants": { + "account_number": "752", + "account_type": "Income Account" + }, + "Subsides en capital et en intérêts": { + "account_number": "753", + "account_type": "Income Account" + }, + "Différences de change": { + "account_number": "754", + "account_type": "Income Account" + }, + "Écarts de conversion des devises": { + "account_number": "755", + "account_type": "Income Account" + }, + "Produits financiers divers (756 à 759)": { + "account_number": "756", + "account_type": "Income Account" + }, + "account_number": "75", + "account_type": "Income Account" + }, + "Produits d'exploitation ou financiers non récurrents": { + "Reprises d'amortissements et de réductions de valeur": { + "sur immobilisations incorporelles": { + "account_number": "7600", + "account_type": "Income Account" + }, + "sur immobilisations corporelles": { + "account_number": "7601", + "account_type": "Income Account" + }, + "account_number": "760", + "account_type": "Income Account" + }, + "Reprises de réductions de valeur sur immobilisations financières": { + "account_number": "761", + "account_type": "Income Account" + }, + "Reprises de provisions pour risques et charges non récurrents": { + "Reprises de provisions pour risques et charges d'exploitation non récurrents": { + "account_number": "7620", + "account_type": "Income Account" + }, + "Reprises de provisions pour risques et charges financiers non récurrents": { + "account_number": "7621", + "account_type": "Income Account" + }, + "account_number": "762", + "account_type": "Income Account" + }, + "Plus-values sur réalisation d'actifs immobilisés": { + "Plus-values sur réalisation d'immobilisations incorporelles et corporelles": { + "account_number": "7630", + "account_type": "Income Account" + }, + "Plus-values sur réalisation d'immobilisations financières": { + "account_number": "7631", + "account_type": "Income Account" + }, + "account_number": "763", + "account_type": "Income Account" + }, + "Autres bénéfices d'exploitation non récurrents (764 à 768)": { + "account_number": "764", + "account_type": "Income Account" + }, + "Autres produits financiers non récurrents": { + "account_number": "769", + "account_type": "Income Account" + }, + "account_number": "76", + "account_type": "Income Account" + }, + "Régularisations d'impôts et reprises de provisions fiscales": { + "Impôts belges sur le résultat": { + "Régularisation d'impôts dus ou versés": { + "account_number": "7710", + "account_type": "Income Account" + }, + "Régularisation d'impôts estimés": { + "account_number": "7711", + "account_type": "Income Account" + }, + "Reprises de provisions fiscales": { + "account_number": "7712", + "account_type": "Income Account" + }, + "account_number": "771", + "account_type": "Income Account" + }, + "Impôts étrangers sur le résultat": { + "account_number": "773", + "account_type": "Income Account" + }, + "account_number": "77", + "account_type": "Income Account" + }, + "Prélèvements sur les réserves immunisées et les impôts différés": { + "Prélèvements sur les impôts différés": { + "account_number": "780", + "account_type": "Income Account" + }, + "Prélèvement sur les réserves immunisées": { + "account_number": "789", + "account_type": "Income Account" + }, + "account_number": "78", + "account_type": "Income Account" + }, + "Affectations et prélèvements": { + "Bénéfice reporté de l'exercice précédent": { + "account_number": "790", + "account_type": "Income Account" + }, + "Prélèvements sur l'apport": { + "account_number": "791", + "account_type": "Income Account" + }, + "Prélèvements sur les réserves": { + "account_number": "792", + "account_type": "Income Account" + }, + "Perte à reporter": { + "account_number": "793", + "account_type": "Income Account" + }, + "Intervention d'associés (ou du propriétaire) dans la perte": { + "account_number": "794", + "account_type": "Income Account" + }, + "account_number": "79", + "account_type": "Income Account" + } + } + } +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index 62b6d5c0b6a..595cc029e39 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -89,13 +89,14 @@ "enable_fuzzy_matching", "reports_tab", "remarks_section", - "general_ledger_remarks_length", + "disable_include_dimensions", "column_break_lvjk", - "receivable_payable_remarks_length", + "general_ledger_remarks_length", "accounts_receivable_payable_tuning_section", "receivable_payable_fetch_method", "default_ageing_range", "column_break_ntmi", + "receivable_payable_remarks_length", "legacy_section", "ignore_is_opening_check_for_reporting", "payment_request_settings", @@ -483,7 +484,7 @@ { "fieldname": "remarks_section", "fieldtype": "Section Break", - "label": "Remarks Column Length" + "label": "General Ledger Report" }, { "default": "0", @@ -566,7 +567,7 @@ { "fieldname": "accounts_receivable_payable_tuning_section", "fieldtype": "Section Break", - "label": "Accounts Receivable / Payable Tuning" + "label": "Accounts Receivable / Payable Report" }, { "fieldname": "legacy_section", @@ -665,6 +666,12 @@ "fieldname": "default_ageing_range", "fieldtype": "Data", "label": "Default Ageing Range" + }, + { + "default": "0", + "fieldname": "disable_include_dimensions", + "fieldtype": "Check", + "label": "Disable \"Consider Accounting Dimension\" Filter" } ], "icon": "icon-cog", @@ -672,7 +679,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2026-06-24 12:59:41.868865", + "modified": "2026-08-14 13:12:47.895908", "modified_by": "Administrator", "module": "Accounts", "name": "Accounts Settings", diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py index 83ece261895..27ed0290827 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py @@ -44,6 +44,7 @@ class AccountsSettings(Document): default_ageing_range: DF.Data | None delete_linked_ledger_entries: DF.Check determine_address_tax_category_from: DF.Literal["Billing Address", "Shipping Address"] + disable_include_dimensions: DF.Check enable_common_party_accounting: DF.Check enable_fuzzy_matching: DF.Check enable_immutable_ledger: DF.Check diff --git a/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.json b/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.json index 8ea57191024..5382fa4f9d6 100644 --- a/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.json +++ b/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.json @@ -94,11 +94,11 @@ "fieldtype": "Column Break" }, { - "allow_on_submit": 1, - "fieldname": "project", - "fieldtype": "Link", - "label": "Project", - "options": "Project" + "allow_on_submit": 1, + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" }, { "fieldname": "section_break_8", @@ -187,12 +187,14 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-11-25 11:10:10.945027", + "modified": "2026-05-01 00:38:53.368737", "modified_by": "Administrator", "module": "Accounts", "name": "Advance Taxes and Charges", "owner": "Administrator", "permissions": [], + "row_format": "Dynamic", "sort_field": "modified", - "sort_order": "ASC" -} \ No newline at end of file + "sort_order": "ASC", + "states": [] +} diff --git a/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.py b/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.py index 47e97ba015a..7e2bcfd5834 100644 --- a/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.py +++ b/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.py @@ -30,6 +30,7 @@ class AdvanceTaxesandCharges(Document): parent: DF.Data parentfield: DF.Data parenttype: DF.Data + project: DF.Link | None rate: DF.Float row_id: DF.Data | None tax_amount: DF.Currency diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py index aefaf8c12fe..db68b6d894d 100644 --- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py +++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py @@ -252,6 +252,7 @@ def get_import_status(docname): import_status = {} data_import = frappe.get_doc("Bank Statement Import", docname) + data_import.check_permission() import_status["status"] = data_import.status logs = frappe.get_all( diff --git a/erpnext/accounts/doctype/budget/budget.py b/erpnext/accounts/doctype/budget/budget.py index e1038b6af33..ae891fb0a1f 100644 --- a/erpnext/accounts/doctype/budget/budget.py +++ b/erpnext/accounts/doctype/budget/budget.py @@ -98,13 +98,13 @@ class Budget(Document): frappe.throw(_("Budget cannot be assigned against Group Account {0}").format(d.account)) elif account_details.company != self.company: frappe.throw( - _("Account {0} does not belongs to company {1}").format(d.account, self.company) + _("Account {0} does not belong to company {1}").format(d.account, self.company) ) elif account_details.report_type != "Profit and Loss": frappe.throw( _( "Budget cannot be assigned against {0}, as its Root Type is not of Income or Expense" - ).format(self.account) + ).format(d.account) ) if d.account in account_list: diff --git a/erpnext/accounts/doctype/budget/test_budget.py b/erpnext/accounts/doctype/budget/test_budget.py index 6d256382042..6cd7aa766bc 100644 --- a/erpnext/accounts/doctype/budget/test_budget.py +++ b/erpnext/accounts/doctype/budget/test_budget.py @@ -357,6 +357,16 @@ class TestBudget(unittest.TestCase): self.assertRaises(BudgetError, jv.submit) + def test_budget_against_balance_sheet_account(self): + budget = frappe.new_doc("Budget") + budget.budget_against = "Cost Center" + budget.cost_center = "_Test Cost Center - _TC" + budget.company = "_Test Company" + budget.fiscal_year = get_fiscal_year(nowdate())[0] + budget.append("accounts", {"account": "_Test Bank - _TC", "budget_amount": 200000}) + + self.assertRaisesRegex(frappe.ValidationError, "_Test Bank - _TC", budget.insert) + def set_total_expense_zero(posting_date, budget_against_field=None, budget_against_CC=None): if budget_against_field == "project": diff --git a/erpnext/accounts/doctype/item_tax_template/item_tax_template.js b/erpnext/accounts/doctype/item_tax_template/item_tax_template.js index b608ccd3568..94c87fcae93 100644 --- a/erpnext/accounts/doctype/item_tax_template/item_tax_template.js +++ b/erpnext/accounts/doctype/item_tax_template/item_tax_template.js @@ -47,3 +47,12 @@ frappe.ui.form.on("Item Tax Template", { }); }, }); + +frappe.ui.form.on("Item Tax Template Detail", { + not_applicable: function (frm, cdt, cdn) { + let row = locals[cdt][cdn]; + if (row.not_applicable) { + frappe.model.set_value(cdt, cdn, "tax_rate", 0); + } + }, +}); diff --git a/erpnext/accounts/doctype/item_tax_template/item_tax_template.py b/erpnext/accounts/doctype/item_tax_template/item_tax_template.py index 02b7455fb9c..57bc2b60f36 100644 --- a/erpnext/accounts/doctype/item_tax_template/item_tax_template.py +++ b/erpnext/accounts/doctype/item_tax_template/item_tax_template.py @@ -27,8 +27,15 @@ class ItemTaxTemplate(Document): # end: auto-generated types def validate(self): + self.set_zero_rate_for_not_applicable_tax() self.validate_tax_accounts() + def set_zero_rate_for_not_applicable_tax(self): + """Ensure tax_rate is 0 for any row marked as not applicable.""" + for row in self.get("taxes"): + if row.not_applicable: + row.tax_rate = 0 + def autoname(self): if self.company and self.title: abbr = frappe.get_cached_value("Company", self.company, "abbr") diff --git a/erpnext/accounts/doctype/item_tax_template/item_tax_template_dashboard.py b/erpnext/accounts/doctype/item_tax_template/item_tax_template_dashboard.py index 5a2bd720dd3..58320b237c3 100644 --- a/erpnext/accounts/doctype/item_tax_template/item_tax_template_dashboard.py +++ b/erpnext/accounts/doctype/item_tax_template/item_tax_template_dashboard.py @@ -8,6 +8,6 @@ def get_data(): {"label": _("Pre Sales"), "items": ["Quotation", "Supplier Quotation"]}, {"label": _("Sales"), "items": ["Sales Invoice", "Sales Order", "Delivery Note"]}, {"label": _("Purchase"), "items": ["Purchase Invoice", "Purchase Order", "Purchase Receipt"]}, - {"label": _("Stock"), "items": ["Item Groups", "Item"]}, + {"label": _("Stock"), "items": ["Item Group", "Item"]}, ], } diff --git a/erpnext/accounts/doctype/item_tax_template_detail/item_tax_template_detail.json b/erpnext/accounts/doctype/item_tax_template_detail/item_tax_template_detail.json index 7e487cccf19..42ef8832fd4 100644 --- a/erpnext/accounts/doctype/item_tax_template_detail/item_tax_template_detail.json +++ b/erpnext/accounts/doctype/item_tax_template_detail/item_tax_template_detail.json @@ -6,7 +6,8 @@ "engine": "InnoDB", "field_order": [ "tax_type", - "tax_rate" + "tax_rate", + "not_applicable" ], "fields": [ { @@ -21,12 +22,21 @@ "fieldname": "tax_rate", "fieldtype": "Float", "in_list_view": 1, - "label": "Tax Rate" + "label": "Tax Rate", + "read_only_depends_on": "eval:doc.not_applicable" + }, + { + "default": "0", + "description": "Check if this tax is not applicable to items (distinct from 0% rate)", + "fieldname": "not_applicable", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Not Applicable" } ], "istable": 1, "links": [], - "modified": "2026-04-30 23:49:27.020639", + "modified": "2026-04-30 23:59:22.020639", "modified_by": "Administrator", "module": "Accounts", "name": "Item Tax Template Detail", diff --git a/erpnext/accounts/doctype/item_tax_template_detail/item_tax_template_detail.py b/erpnext/accounts/doctype/item_tax_template_detail/item_tax_template_detail.py index 810235e3691..a98fbc6ba86 100644 --- a/erpnext/accounts/doctype/item_tax_template_detail/item_tax_template_detail.py +++ b/erpnext/accounts/doctype/item_tax_template_detail/item_tax_template_detail.py @@ -14,6 +14,7 @@ class ItemTaxTemplateDetail(Document): if TYPE_CHECKING: from frappe.types import DF + not_applicable: DF.Check parent: DF.Data parentfield: DF.Data parenttype: DF.Data diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js index 47ba392802e..b4f7bfeefba 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.js +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js @@ -65,7 +65,7 @@ frappe.ui.form.on("Journal Entry", { ); } - if (frm.doc.docstatus == 1) { + if (frm.doc.docstatus == 1 && !frm.doc.reversal_of) { frm.add_custom_button( __("Reverse Journal Entry"), function () { @@ -516,7 +516,7 @@ $.extend(erpnext.journal_entry, { lock_reversal_entry: function (frm) { frm.fields .filter((field) => field.has_input) - .filter((field) => field.df.fieldname != "posting_date") + .filter((field) => !["posting_date", "user_remark"].includes(field.df.fieldname)) .forEach((field) => frm.set_df_property(field.df.fieldname, "read_only", 1)); frm.set_df_property("accounts", "read_only", 1); }, diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 8acd5cf8587..bccf718f4a6 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -7,6 +7,7 @@ import json import frappe from frappe import _, msgprint, scrub from frappe.core.doctype.submission_queue.submission_queue import queue_submission +from frappe.model.document import Document from frappe.utils import comma_and, cstr, flt, fmt_money, formatdate, get_link_to_form, getdate, nowdate import erpnext @@ -1892,7 +1893,21 @@ def make_inter_company_journal_entry(name, voucher_type, company): @frappe.whitelist() -def make_reverse_journal_entry(source_name, target_doc=None): +def make_reverse_journal_entry(source_name: str, target_doc: str | dict | Document | None = None) -> Document: + # `get_mapped_doc` checks this as well, but the guard below discloses which entry + # reverses which, so read access has to be settled before it runs + if not frappe.has_permission("Journal Entry", doc=source_name): + frappe.throw(_("Not permitted"), frappe.PermissionError) + + reversal_of = frappe.db.get_value("Journal Entry", source_name, "reversal_of") + if reversal_of: + frappe.throw( + _("{0} is already a Reverse Journal Entry of {1}. Cancel it instead of reversing it.").format( + get_link_to_form("Journal Entry", source_name), + get_link_to_form("Journal Entry", reversal_of), + ) + ) + from frappe.model.mapper import get_mapped_doc def post_process(source, target): diff --git a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py index 62e74d02033..61ab04d2a8b 100644 --- a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py @@ -249,6 +249,27 @@ class TestJournalEntry(unittest.TestCase): self.check_gl_entries() + def test_disallow_reversal_of_a_reversal_journal_entry(self): + from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry + + jv = make_journal_entry("_Test Bank - _TC", "Sales - _TC", 100, submit=True) + + rjv = make_reverse_journal_entry(jv.name) + rjv.posting_date = nowdate() + rjv.submit() + + self.assertRaisesRegex( + frappe.ValidationError, + "is already a Reverse Journal Entry", + make_reverse_journal_entry, + rjv.name, + ) + + # the guard must not disclose the reversal to a user who cannot read the entry + frappe.set_user("Guest") + self.addCleanup(frappe.set_user, "Administrator") + self.assertRaises(frappe.PermissionError, make_reverse_journal_entry, rjv.name) + def test_disallow_change_in_account_currency_for_a_party(self): # create jv in USD jv = make_journal_entry("_Test Bank USD - _TC", "_Test Receivable USD - _TC", 100, save=False) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index afc08c0e4d6..e4cc191ffb0 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -291,6 +291,7 @@ class PurchaseInvoice(BuyingController): self.validate_multiple_billing("Purchase Receipt", "pr_detail", "amount") self.set_status() self.validate_purchase_receipt_if_update_stock() + self.validate_exchange_rate_with_purchase_receipt() validate_inter_company_party( self.doctype, self.supplier, self.company, self.inter_company_invoice_reference ) @@ -313,6 +314,47 @@ class PurchaseInvoice(BuyingController): if total_billed_qty and total_received_qty: self.per_received = total_received_qty / total_billed_qty * 100 + def validate_exchange_rate_with_purchase_receipt(self): + if self.is_internal_transfer() or not erpnext.is_perpetual_inventory_enabled(self.company): + return + + stock_items = self.get_stock_items() + receipts = { + item.purchase_receipt + for item in self.items + if item.purchase_receipt and item.item_code in stock_items + } + if not receipts: + return + + if frappe.db.get_single_value("Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate"): + return + + mismatched = [ + f"{frappe.bold(row.name)} ({row.conversion_rate})" + for row in frappe.get_all( + "Purchase Receipt", + filters={"name": ("in", list(receipts))}, + fields=["name", "currency", "conversion_rate"], + ) + if row.currency == self.currency + and flt(row.conversion_rate) + and flt(row.conversion_rate) != flt(self.conversion_rate) + ] + if not mismatched: + return + + frappe.throw( + _( + "Exchange rate {0} does not match the exchange rate of Purchase Receipt {1}. Use the same exchange rate as the Purchase Receipt or enable {2} in {3} to adjust the landed cost based on this invoice." + ).format( + frappe.bold(self.conversion_rate), + ", ".join(mismatched), + frappe.bold(_("Set Landed Cost Based on Purchase Invoice Rate")), + get_link_to_form("Buying Settings", "Buying Settings", _("Buying Settings")), + ) + ) + def validate_invoice_hold(self): if self.is_return: frappe.throw(_("Return Purchase Invoice cannot be held.")) @@ -396,6 +438,9 @@ class PurchaseInvoice(BuyingController): self.party_account_currency = account.account_currency def check_on_hold_or_closed_status(self): + if self.get("is_return"): + return + check_list = [] for d in self.get("items"): @@ -1375,7 +1420,20 @@ class PurchaseInvoice(BuyingController): ) if flt(stock_amount, net_amt_precision) != flt(warehouse_debit_amount, net_amt_precision): - cost_of_goods_sold_account = self.get_company_default("default_expense_account") + stock_asset_rbnb = ( + self.get_company_default("asset_received_but_not_billed", ignore_validation=True) + if item.is_fixed_asset + else self.get_company_default("stock_received_but_not_billed", ignore_validation=True) + ) + fallback_account = ( + (item.expense_account or stock_asset_rbnb) + if self.is_return + else (stock_asset_rbnb or item.expense_account) + ) + cost_of_goods_sold_account = ( + self.get_company_default("default_expense_account", ignore_validation=True) + or fallback_account + ) stock_adjustment_amt = stock_amount - warehouse_debit_amount gl_entries.append( @@ -1400,7 +1458,20 @@ class PurchaseInvoice(BuyingController): and warehouse_debit_amount != flt(voucher_wise_stock_value.get((item.name, item.warehouse)), net_amt_precision) ): - cost_of_goods_sold_account = self.get_company_default("default_expense_account") + stock_asset_rbnb = ( + self.get_company_default("asset_received_but_not_billed", ignore_validation=True) + if item.is_fixed_asset + else self.get_company_default("stock_received_but_not_billed", ignore_validation=True) + ) + fallback_account = ( + (item.expense_account or stock_asset_rbnb) + if self.is_return + else (stock_asset_rbnb or item.expense_account) + ) + cost_of_goods_sold_account = ( + self.get_company_default("default_expense_account", ignore_validation=True) + or fallback_account + ) stock_amount = flt(voucher_wise_stock_value.get((item.name, item.warehouse)), net_amt_precision) stock_adjustment_amt = warehouse_debit_amount - stock_amount diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index ae9b8442c34..44d94499516 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -513,6 +513,12 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): ) frappe.db.set_single_value("Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 0) + self.addCleanup( + frappe.db.set_single_value, + "Buying Settings", + "set_landed_cost_based_on_purchase_invoice_rate", + original_value, + ) pr = make_purchase_receipt( company="_Test Company with perpetual inventory", @@ -524,25 +530,15 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): pi = create_purchase_invoice(pr.name) pi.conversion_rate = 80 + self.assertRaises(frappe.ValidationError, pi.insert) + + pi.conversion_rate = 70 pi.insert() pi.submit() - # Get exchnage gain and loss account exchange_gain_loss_account = frappe.db.get_value("Company", pi.company, "exchange_gain_loss_account") - - # fetching the latest GL Entry with exchange gain and loss account account - amount = frappe.db.get_value( - "GL Entry", {"account": exchange_gain_loss_account, "voucher_no": pi.name}, "debit" - ) - - discrepancy_caused_by_exchange_rate_diff = abs( - pi.items[0].base_net_amount - pr.items[0].base_net_amount - ) - - self.assertEqual(discrepancy_caused_by_exchange_rate_diff, amount) - - frappe.db.set_single_value( - "Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", original_value + self.assertFalse( + frappe.db.exists("GL Entry", {"account": exchange_gain_loss_account, "voucher_no": pi.name}) ) def test_purchase_invoice_with_exchange_rate_difference_for_non_stock_item(self): @@ -550,11 +546,21 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): make_purchase_invoice as create_purchase_invoice, ) - # Creating Purchase Invoice with USD currency + original_value = frappe.db.get_single_value( + "Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate" + ) + frappe.db.set_single_value("Buying Settings", "set_landed_cost_based_on_purchase_invoice_rate", 0) + self.addCleanup( + frappe.db.set_single_value, + "Buying Settings", + "set_landed_cost_based_on_purchase_invoice_rate", + original_value, + ) + pr = frappe.new_doc("Purchase Receipt") pr.currency = "USD" pr.company = "_Test Company with perpetual inventory" - pr.conversion_rate = (70,) + pr.conversion_rate = 80 pr.supplier = "_Test Supplier USD" pr.append( "items", @@ -564,34 +570,20 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): "rate": 100, }, ) - pr.append( - "items", - {"item_code": "_Test Item", "qty": 1, "rate": 5, "warehouse": "Stores - TCP1"}, - ) pr.insert() pr.submit() - # Createing purchase invoice against Purchase Receipt pi = create_purchase_invoice(pr.name) - pi.conversion_rate = 80 + pi.conversion_rate = 70 pi.credit_to = "_Test Payable USD - TCP1" pi.insert() pi.submit() - # Get exchnage gain and loss account exchange_gain_loss_account = frappe.db.get_value("Company", pi.company, "exchange_gain_loss_account") - - # fetching the latest GL Entry with exchange gain and loss account account - amount = frappe.db.get_value( - "GL Entry", {"account": exchange_gain_loss_account, "voucher_no": pi.name}, "debit" + self.assertFalse( + frappe.db.exists("GL Entry", {"account": exchange_gain_loss_account, "voucher_no": pi.name}) ) - discrepancy_caused_by_exchange_rate_diff = abs( - pi.items[1].base_net_amount - pr.items[1].base_net_amount - ) - - self.assertEqual(discrepancy_caused_by_exchange_rate_diff, amount) - def test_purchase_invoice_change_naming_series(self): pi = frappe.copy_doc(test_records[1]) pi.insert() @@ -1662,6 +1654,96 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): ) frappe.db.set_value("Company", "_Test Company", "exchange_gain_loss_account", original_account) + def test_stock_adjustment_account_fallbacks_when_default_expense_account_unset(self): + from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import PurchaseInvoice + + class StockAdjustmentInvoice: + company = "_Test Company" + conversion_rate = 1 + update_stock = 1 + is_internal_supplier = 0 + return_against = None + project = None + + def __init__(self, is_return, defaults): + self.is_return = is_return + self.defaults = defaults + + def get(self, fieldname): + return None + + def get_company_default(self, fieldname, ignore_validation=False): + return self.defaults.get(fieldname) + + def get_gl_dict(self, args, *unused_args, **unused_kwargs): + return frappe._dict(args) + + def make_invoice(is_return, defaults): + return StockAdjustmentInvoice(is_return, defaults) + + def make_item(is_fixed_asset=0, expense_account="Item Expense - _TC"): + return frappe._dict( + { + "name": "row-1", + "warehouse": "Stores - _TC", + "valuation_rate": 10, + "qty": 10, + "conversion_factor": 1, + "base_net_amount": 100, + "item_tax_amount": 0, + "landed_cost_voucher_amount": 0, + "sales_incoming_rate": 0, + "is_fixed_asset": is_fixed_asset, + "expense_account": expense_account, + "cost_center": "Main - _TC", + "project": None, + "precision": lambda fieldname: 2, + } + ) + + defaults = { + "default_expense_account": None, + "stock_received_but_not_billed": "Stock Received But Not Billed - _TC", + "asset_received_but_not_billed": "Asset Received But Not Billed - _TC", + } + test_cases = ( + ( + "company default expense", + 0, + make_item(), + {**defaults, "default_expense_account": "Default Expense - _TC"}, + "Default Expense - _TC", + ), + ("stock rbnb", 0, make_item(), defaults, "Stock Received But Not Billed - _TC"), + ( + "asset rbnb", + 0, + make_item(is_fixed_asset=1), + defaults, + "Asset Received But Not Billed - _TC", + ), + ("return item expense", 1, make_item(), defaults, "Item Expense - _TC"), + ( + "return without item expense", + 1, + make_item(expense_account=None), + defaults, + "Stock Received But Not Billed - _TC", + ), + ) + + for label, is_return, item, company_defaults, expected_account in test_cases: + with self.subTest(label=label): + invoice = make_invoice(is_return, company_defaults) + gl_entries = [] + PurchaseInvoice.make_stock_adjustment_entry( + invoice, gl_entries, item, {(item.name, item.warehouse): 90}, "INR" + ) + + self.assertEqual(gl_entries[0].account, expected_account) + self.assertEqual(gl_entries[0].debit, 10) + self.assertEqual(gl_entries[0].debit_in_transaction_currency, 10) + @change_settings("Accounts Settings", {"unlink_payment_on_cancellation_of_invoice": 1}) def test_purchase_invoice_advance_taxes(self): from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry @@ -2609,6 +2691,39 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): self.assertEqual(row.serial_no, "\n".join(serial_nos[:2])) self.assertEqual(row.rejected_serial_no, serial_nos[2]) + def test_purchase_invoice_return_against_closed_purchase_order(self): + from erpnext.controllers.sales_and_purchase_return import make_return_doc + + po = create_purchase_order(qty=2, rate=100) + + invoices = [] + for _ in range(2): + pi = make_pi_from_po(po.name) + pi.items[0].qty = 1 + pi.submit() + invoices.append(pi) + + make_return_doc("Purchase Invoice", invoices[0].name).submit() + + po.reload() + po.update_status("Closed") + + # a debit note against a closed Purchase Order should still go through, + # the same way a Sales Invoice return does against a closed Sales Order + debit_note = make_return_doc("Purchase Invoice", invoices[1].name) + debit_note.submit() + + self.assertEqual(debit_note.docstatus, 1) + self.assertEqual(frappe.db.get_value("Purchase Order", po.name, "status"), "Closed") + + # cancelling the debit note runs the same check on the closed order + debit_note.reload() + debit_note.cancel() + + # a regular invoice against the closed order must still be blocked + blocked_pi = make_pi_from_po(po.name) + self.assertRaisesRegex(frappe.InvalidStatusError, "Closed", blocked_pi.save) + def test_make_pr_and_pi_from_po(self): from erpnext.assets.doctype.asset.test_asset import create_asset_category diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json index ea26d2b5460..aa6a3c5a1f2 100644 --- a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json +++ b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json @@ -25,10 +25,12 @@ "project", "section_break_9", "account_currency", + "net_amount", "tax_amount", "tax_amount_after_discount_amount", "total", "column_break_14", + "base_net_amount", "base_tax_amount", "base_total", "base_tax_amount_after_discount_amount", @@ -213,11 +215,11 @@ "fieldtype": "Column Break" }, { - "allow_on_submit": 1, - "fieldname": "project", - "fieldtype": "Link", - "label": "Project", - "options": "Project" + "allow_on_submit": 1, + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" }, { "default": "0", @@ -241,20 +243,38 @@ "fieldtype": "Check", "label": "Is Tax Withholding Account", "read_only": 1 + }, + { + "description": "Basis for tax calculation", + "fieldname": "net_amount", + "fieldtype": "Currency", + "label": "Net Amount", + "options": "currency", + "read_only": 1 + }, + { + "description": "Basis for tax calculation", + "fieldname": "base_net_amount", + "fieldtype": "Currency", + "label": "Net Amount (Company Currency)", + "options": "Company:company:default_currency", + "read_only": 1 } ], "grid_page_length": 50, "idx": 1, "istable": 1, "links": [], - "modified": "2025-04-15 13:14:48.936047", + "modified": "2026-05-01 00:38:29.543523", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Taxes and Charges", "naming_rule": "Random", "owner": "Administrator", "permissions": [], + "row_format": "Dynamic", "sort_field": "modified", "sort_order": "DESC", + "states": [], "track_changes": 1 -} +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.py b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.py index 585d5e65ad1..66c2b29d04b 100644 --- a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.py +++ b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.py @@ -17,6 +17,7 @@ class PurchaseTaxesandCharges(Document): account_currency: DF.Link | None account_head: DF.Link add_deduct_tax: DF.Literal["Add", "Deduct"] + base_net_amount: DF.Currency base_tax_amount: DF.Currency base_tax_amount_after_discount_amount: DF.Currency base_total: DF.Currency @@ -35,9 +36,11 @@ class PurchaseTaxesandCharges(Document): included_in_print_rate: DF.Check is_tax_withholding_account: DF.Check item_wise_tax_detail: DF.Code | None + net_amount: DF.Currency parent: DF.Data parentfield: DF.Data parenttype: DF.Data + project: DF.Link | None rate: DF.Float row_id: DF.Data | None tax_amount: DF.Currency diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 53e35e7407f..59e72ced503 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -25,9 +25,9 @@ from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category from erpnext.accounts.general_ledger import get_round_off_account_and_cost_center from erpnext.accounts.party import ( CROSS_PARTY_FIELD_NO_MAP, + _get_party_details, get_due_date, get_party_account, - get_party_details, ) from erpnext.accounts.utils import ( cancel_exchange_gain_loss_journal, @@ -2266,9 +2266,9 @@ def make_delivery_note(source_name, target_doc=None): "cost_center": "cost_center", }, "postprocess": update_item, - "condition": lambda doc: doc.delivered_by_supplier != 1 - and not doc.dn_detail - and doc.qty - doc.delivered_qty > 0, + "condition": lambda doc: ( + doc.delivered_by_supplier != 1 and not doc.dn_detail and doc.qty - doc.delivered_qty > 0 + ), }, "Sales Taxes and Charges": {"doctype": "Sales Taxes and Charges", "reset_value": True}, "Sales Team": { @@ -2737,7 +2737,7 @@ def update_taxes( master_doctype=None, ): # Update Party Details - party_details = get_party_details( + party_details = _get_party_details( party=party, party_type=party_type, company=company, diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json index 8f7b1ece3c7..96992b364a0 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json +++ b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json @@ -21,10 +21,12 @@ "rate", "section_break_9", "account_currency", + "net_amount", "tax_amount", "total", "tax_amount_after_discount_amount", "column_break_13", + "base_net_amount", "base_tax_amount", "base_total", "base_tax_amount_after_discount_amount", @@ -190,11 +192,11 @@ "fieldtype": "Column Break" }, { - "allow_on_submit": 1, - "fieldname": "project", - "fieldtype": "Link", - "label": "Project", - "options": "Project" + "allow_on_submit": 1, + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" }, { "default": "0", @@ -220,19 +222,36 @@ "label": "Account Currency", "options": "Currency", "read_only": 1 + }, + { + "description": "Basis for tax calculation", + "fieldname": "net_amount", + "fieldtype": "Currency", + "label": "Net Amount", + "options": "currency", + "read_only": 1 + }, + { + "description": "Basis for tax calculation", + "fieldname": "base_net_amount", + "fieldtype": "Currency", + "label": "Net Amount (Company Currency)", + "options": "Company:company:default_currency", + "read_only": 1 } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2024-01-14 10:08:17.776528", + "modified": "2026-05-01 00:37:57.880071", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Taxes and Charges", "owner": "Administrator", "permissions": [], + "row_format": "Dynamic", "sort_field": "modified", "sort_order": "ASC", "states": [] -} +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.py b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.py index 7936178fda8..6aa05432622 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.py +++ b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.py @@ -16,6 +16,7 @@ class SalesTaxesandCharges(Document): account_currency: DF.Link | None account_head: DF.Link + base_net_amount: DF.Currency base_tax_amount: DF.Currency base_tax_amount_after_discount_amount: DF.Currency base_total: DF.Currency @@ -33,9 +34,11 @@ class SalesTaxesandCharges(Document): included_in_paid_amount: DF.Check included_in_print_rate: DF.Check item_wise_tax_detail: DF.Code | None + net_amount: DF.Currency parent: DF.Data parentfield: DF.Data parenttype: DF.Data + project: DF.Link | None rate: DF.Float row_id: DF.Data | None tax_amount: DF.Currency diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py index 6432acaae93..fca17cc14ec 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py +++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template_dashboard.py @@ -7,10 +7,9 @@ def get_data(): "non_standard_fieldnames": { "Tax Rule": "sales_tax_template", "Subscription": "sales_tax_template", - "Restaurant": "default_tax_template", }, "transactions": [ {"label": _("Transactions"), "items": ["Sales Invoice", "Sales Order", "Delivery Note"]}, - {"label": _("References"), "items": ["POS Profile", "Subscription", "Restaurant", "Tax Rule"]}, + {"label": _("References"), "items": ["POS Profile", "Subscription", "Tax Rule"]}, ], } diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 170a39582af..1747fe63480 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -83,7 +83,6 @@ def get_party_details( price_list=None, currency=None, doctype=None, - ignore_permissions=False, fetch_payment_terms_template=True, party_address=None, company_address=None, @@ -93,8 +92,6 @@ def get_party_details( ): if not party: return frappe._dict() - if not frappe.db.exists(party_type, party): - frappe.throw(_("{0}: {1} does not exists").format(party_type, party)) return _get_party_details( party, account, @@ -105,7 +102,7 @@ def get_party_details( price_list, currency, doctype, - ignore_permissions, + False, fetch_payment_terms_template, party_address, company_address, diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js index 8de9d60a8fd..50920ceecb4 100644 --- a/erpnext/accounts/report/accounts_payable/accounts_payable.js +++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js @@ -94,10 +94,15 @@ frappe.query_reports["Accounts Payable"] = { options: get_party_type_options(), on_change: function () { frappe.query_report.set_filter_value("party", ""); - frappe.query_report.toggle_filter_display( - "supplier_group", - frappe.query_report.get_filter_value("party_type") !== "Supplier" - ); + let is_supplier = frappe.query_report.get_filter_value("party_type") === "Supplier"; + let supplier_group_filter = frappe.query_report.get_filter("supplier_group"); + if (supplier_group_filter) { + supplier_group_filter.df.hidden = !is_supplier; + } + frappe.query_report.toggle_filter_display("supplier_group", !is_supplier); + if (!is_supplier) { + frappe.query_report.set_filter_value("supplier_group", []); + } }, }, { diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.js b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.js index c28815df62e..136c09dbe21 100644 --- a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.js +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.js @@ -93,5 +93,27 @@ frappe.query_reports["Customer Ledger Summary"] = { fieldtype: "Data", hidden: 1, }, + { + fieldname: "cost_center", + label: __("Cost Center"), + fieldtype: "MultiSelectList", + options: "Cost Center", + get_data: function (txt) { + return frappe.db.get_link_options("Cost Center", txt, { + company: frappe.query_report.get_filter_value("company"), + }); + }, + }, + { + fieldname: "project", + label: __("Project"), + fieldtype: "MultiSelectList", + options: "Project", + get_data: function (txt) { + return frappe.db.get_link_options("Project", txt, { + company: frappe.query_report.get_filter_value("company"), + }); + }, + }, ], }; diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js index c8470bc4c3f..ec24ec900a1 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.js +++ b/erpnext/accounts/report/general_ledger/general_ledger.js @@ -174,7 +174,7 @@ frappe.query_reports["General Ledger"] = { fieldname: "include_dimensions", label: __("Consider Accounting Dimensions"), fieldtype: "Check", - default: 1, + default: frappe.boot.sysdefaults.disable_include_dimensions ? 0 : 1, }, { fieldname: "disable_opening_balance_calculation", diff --git a/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js index 5d91575b8b2..535bc7bfad2 100644 --- a/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js +++ b/erpnext/accounts/report/supplier_ledger_summary/supplier_ledger_summary.js @@ -74,5 +74,27 @@ frappe.query_reports["Supplier Ledger Summary"] = { fieldtype: "Data", hidden: 1, }, + { + fieldname: "cost_center", + label: __("Cost Center"), + fieldtype: "MultiSelectList", + options: "Cost Center", + get_data: function (txt) { + return frappe.db.get_link_options("Cost Center", txt, { + company: frappe.query_report.get_filter_value("company"), + }); + }, + }, + { + fieldname: "project", + label: __("Project"), + fieldtype: "MultiSelectList", + options: "Project", + get_data: function (txt) { + return frappe.db.get_link_options("Project", txt, { + company: frappe.query_report.get_filter_value("company"), + }); + }, + }, ], }; diff --git a/erpnext/accounts/test/test_utils.py b/erpnext/accounts/test/test_utils.py index b86c8161f03..41e3c4f0451 100644 --- a/erpnext/accounts/test/test_utils.py +++ b/erpnext/accounts/test/test_utils.py @@ -7,6 +7,7 @@ from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_ent from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice from erpnext.accounts.party import get_party_shipping_address from erpnext.accounts.utils import ( + get_currency_precision, get_future_stock_vouchers, get_voucherwise_gl_entries, get_zero_cutoff, @@ -164,6 +165,21 @@ class TestUtils(unittest.TestCase): self.assertEqual(get_zero_cutoff("EUR"), 0.005) self.assertEqual(get_zero_cutoff("BHD"), 0.0005) + def test_get_currency_precision_respects_zero_and_fallback(self): + currency_precision = frappe.db.get_default("currency_precision") + number_format = frappe.db.get_default("number_format") + + try: + frappe.db.set_default("number_format", "#,###.##") + frappe.db.set_default("currency_precision", "0") + self.assertEqual(get_currency_precision(), 0) + + frappe.db.set_default("currency_precision", "") + self.assertEqual(get_currency_precision(), 2) + finally: + frappe.db.set_default("currency_precision", currency_precision or "") + frappe.db.set_default("number_format", number_format or "#,###.##") + ADDRESS_RECORDS = [ { diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 05b4c0219a3..5f55df4608d 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -1131,12 +1131,12 @@ def fix_total_debit_credit(): def get_currency_precision(): - precision = cint(frappe.db.get_default("currency_precision")) - if not precision: - number_format = frappe.db.get_default("number_format") or "#,###.##" - precision = get_number_format_info(number_format)[2] + currency_precision = frappe.db.get_default("currency_precision") + if currency_precision not in (None, ""): + return cint(currency_precision) - return precision + number_format = frappe.db.get_default("number_format") or "#,###.##" + return get_number_format_info(number_format)[2] def get_fraction_units(currency: str) -> int: diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index ea8059b68a5..1abb8b73277 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -81,7 +81,7 @@ def post_depreciation_entries(date=None): ) try: - make_depreciation_entry( + _make_depreciation_entry( asset_depr_schedule_name, date, sch_start_idx, @@ -139,7 +139,7 @@ def get_depreciable_asset_depr_schedules_data(date): def make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date=None): for row in asset_doc.get("finance_books"): asset_depr_schedule_name = get_asset_depr_schedule_name(asset_doc.name, "Active", row.finance_book) - make_depreciation_entry(asset_depr_schedule_name, date) + _make_depreciation_entry(asset_depr_schedule_name, date) def get_acc_frozen_upto(): @@ -193,6 +193,30 @@ def make_depreciation_entry( credit_and_debit_accounts=None, depreciation_cost_center_and_depreciation_series=None, accounting_dimensions=None, +): + asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) + frappe.has_permission("Asset Depreciation Schedule", "write", asset_depr_schedule_doc, throw=True) + frappe.has_permission("Asset", "write", asset_depr_schedule_doc.asset, throw=True) + + return _make_depreciation_entry( + asset_depr_schedule_name, + date, + sch_start_idx, + sch_end_idx, + credit_and_debit_accounts, + depreciation_cost_center_and_depreciation_series, + accounting_dimensions, + ) + + +def _make_depreciation_entry( + asset_depr_schedule_name, + date=None, + sch_start_idx=None, + sch_end_idx=None, + credit_and_debit_accounts=None, + depreciation_cost_center_and_depreciation_series=None, + accounting_dimensions=None, ): frappe.has_permission("Journal Entry", throw=True) @@ -395,6 +419,7 @@ def get_comma_separated_links(names, doctype): @frappe.whitelist() def scrap_asset(asset_name, scrap_date=None): + frappe.has_permission("Asset", "write", asset_name, throw=True) asset = frappe.get_doc("Asset", asset_name) if asset.docstatus != 1: @@ -472,6 +497,7 @@ def validate_scrap_date(scrap_date, today_date, purchase_date, calculate_depreci @frappe.whitelist() def restore_asset(asset_name): + frappe.has_permission("Asset", "write", asset_name, throw=True) asset = frappe.get_doc("Asset", asset_name) reverse_depreciation_entry_made_after_disposal(asset, asset.disposal_date) diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py index 15128607e5b..9ac50458e1e 100644 --- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py @@ -166,6 +166,8 @@ class AssetCapitalization(StockController): if d.meta.has_field(k) and (not d.get(k) or k in force_fields): d.set(k, v) + self.split_valuation_rate_for_grouped_stock_items() + for d in self.asset_items: args = self.as_dict() args.update(d.as_dict()) @@ -187,6 +189,30 @@ class AssetCapitalization(StockController): if d.meta.has_field(k) and (not d.get(k) or k in force_fields): d.set(k, v) + def split_valuation_rate_for_grouped_stock_items(self): + groups = {} + for d in self.stock_items: + if d.item_code and d.warehouse and not (d.serial_no or d.batch_no or d.serial_and_batch_bundle): + groups.setdefault((d.item_code, d.warehouse), []).append(d) + + for rows in groups.values(): + if len(rows) < 2: + continue + + cumulative_qty = 0.0 + prev_cumulative_value = 0.0 + for d in rows: + cumulative_qty += flt(d.stock_qty) + args = self.get_args_for_incoming_rate(d) + args["qty"] = -1 * cumulative_qty + cumulative_rate = flt(get_incoming_rate(args, raise_error_if_no_rate=False)) + cumulative_value = cumulative_rate * cumulative_qty + + row_value = cumulative_value - prev_cumulative_value + d.valuation_rate = flt(row_value / d.stock_qty) if flt(d.stock_qty) else 0.0 + d.amount = flt(flt(d.stock_qty) * d.valuation_rate, d.precision("amount")) + prev_cumulative_value = cumulative_value + def validate_target_item(self): target_item = frappe.get_cached_doc("Item", self.target_item_code) @@ -338,6 +364,8 @@ class AssetCapitalization(StockController): warehouse_details = get_warehouse_details(args) d.update(warehouse_details) + self.split_valuation_rate_for_grouped_stock_items() + @frappe.whitelist() def set_asset_values(self): for d in self.get("asset_items"): diff --git a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py index e0ff6102046..bdd61e6b29a 100644 --- a/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py +++ b/erpnext/assets/doctype/asset_capitalization/test_asset_capitalization.py @@ -10,12 +10,14 @@ from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries from erpnext.assets.doctype.asset.test_asset import ( create_asset, create_asset_data, + create_fixed_asset_item, set_depreciation_settings_in_company, ) from erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( get_asset_depr_schedule_doc, ) from erpnext.stock.doctype.item.test_item import create_item +from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt from erpnext.stock.doctype.serial_and_batch_bundle.test_serial_and_batch_bundle import ( make_serial_batch_bundle, ) @@ -340,6 +342,33 @@ class TestAssetCapitalization(unittest.TestCase): self.assertFalse(get_actual_gle_dict(asset_capitalization.name)) self.assertFalse(get_actual_sle_dict(asset_capitalization.name)) + def test_grouped_stock_item_rows_split_fifo_rate(self): + from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse + + company = "_Test Company" + warehouse = create_warehouse("_Test Warehouse for Grouped FIFO Rows", company=company) + item = create_item( + "_Test Grouped FIFO Rows Item", is_stock_item=1, is_fixed_asset=0, is_purchase_item=1 + ) + target_item = create_fixed_asset_item("_Test Grouped FIFO Rows Target Item") + + make_purchase_receipt(item_code=item.item_code, qty=1, rate=100, company=company, warehouse=warehouse) + make_purchase_receipt(item_code=item.item_code, qty=1, rate=200, company=company, warehouse=warehouse) + + asset_capitalization = frappe.new_doc("Asset Capitalization") + asset_capitalization.company = company + asset_capitalization.target_item_code = target_item.name + asset_capitalization.append( + "stock_items", {"item_code": item.item_code, "warehouse": warehouse, "stock_qty": 1} + ) + asset_capitalization.append( + "stock_items", {"item_code": item.item_code, "warehouse": warehouse, "stock_qty": 1} + ) + asset_capitalization.insert() + + rates = [d.valuation_rate for d in asset_capitalization.stock_items] + self.assertEqual(rates, [100, 200]) + def create_asset_capitalization_data(): create_item("Capitalization Target Stock Item", is_stock_item=1, is_fixed_asset=0, is_purchase_item=0) diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py index c4ada801cd2..4483ce7c79a 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py @@ -9,13 +9,18 @@ from frappe import _ from frappe.contacts.doctype.contact.contact import get_full_name from frappe.core.doctype.communication.email import make from frappe.desk.form.load import get_attachments +from frappe.model.document import Document from frappe.model.mapper import get_mapped_doc from frappe.query_builder import Order from frappe.utils import get_url from frappe.utils.print_format import download_pdf from frappe.utils.user import get_user_fullname -from erpnext.accounts.party import get_party_account_currency, get_party_details +from erpnext.accounts.party import ( + _get_party_details, + get_party_account_currency, + validate_party_frozen_disabled, +) from erpnext.buying.utils import validate_for_items from erpnext.controllers.buying_controller import BuyingController from erpnext.stock.doctype.material_request.material_request import set_missing_values @@ -123,6 +128,8 @@ class RequestforQuotation(BuyingController): def validate_supplier_list(self): for d in self.suppliers: + validate_party_frozen_disabled("Supplier", d.supplier) + prevent_rfqs = frappe.db.get_value("Supplier", d.supplier, "prevent_rfqs") if prevent_rfqs: standing = frappe.db.get_value("Supplier Scorecard", d.supplier, "status") @@ -443,7 +450,7 @@ def make_supplier_quotation_from_rfq(source_name, target_doc=None, for_supplier= def postprocess(source, target_doc): if for_supplier: target_doc.supplier = for_supplier - args = get_party_details(for_supplier, party_type="Supplier", ignore_permissions=True) + args = _get_party_details(for_supplier, party_type="Supplier", ignore_permissions=True) target_doc.currency = args.currency or get_party_account_currency( "Supplier", for_supplier, source.company ) @@ -479,36 +486,73 @@ def make_supplier_quotation_from_rfq(source_name, target_doc=None, for_supplier= # This method is used to make supplier quotation from supplier's portal. @frappe.whitelist() -def create_supplier_quotation(doc): +def create_supplier_quotation(doc: str | Document | dict): if isinstance(doc, str): doc = json.loads(doc) + supplier = doc.get("supplier") - if frappe.session.user not in frappe.get_all( - "Portal User", {"parent": doc.get("supplier")}, pluck="user" - ): + if frappe.session.user not in frappe.get_all("Portal User", {"parent": supplier}, pluck="user"): frappe.throw(_("Not Permitted"), frappe.PermissionError) - try: - sq_doc = frappe.get_doc( - { - "doctype": "Supplier Quotation", - "supplier": doc.get("supplier"), - "terms": doc.get("terms"), - "company": doc.get("company"), - "currency": doc.get("currency") - or get_party_account_currency("Supplier", doc.get("supplier"), doc.get("company")), - "buying_price_list": doc.get("buying_price_list") - or frappe.db.get_value("Buying Settings", None, "buying_price_list"), - } + validate_existing_supplier_quotation(supplier, doc.get("items")) + + sq_doc = frappe.get_doc( + { + "doctype": "Supplier Quotation", + "supplier": supplier, + "terms": doc.get("terms"), + "company": doc.get("company"), + "currency": doc.get("currency") + or get_party_account_currency("Supplier", supplier, doc.get("company")), + "buying_price_list": doc.get("buying_price_list") + or frappe.db.get_single_value("Buying Settings", "buying_price_list"), + } + ) + add_items(sq_doc, supplier, doc.get("items")) + sq_doc.flags.ignore_permissions = True + sq_doc.run_method("set_missing_values") + sq_doc.save() + frappe.msgprint(_("Supplier Quotation {0} Created").format(sq_doc.name)) + return sq_doc.name + + +def validate_existing_supplier_quotation(supplier, items): + request_for_quotations = {item.get("parent") for item in items if item.get("parent")} + if not request_for_quotations: + return + + rfq = frappe.qb.DocType("Request for Quotation") + ( + frappe.qb.from_(rfq) + .select(rfq.name) + .where(rfq.name.isin(request_for_quotations)) + .orderby(rfq.name) + .for_update() + ).run() + + sq = frappe.qb.DocType("Supplier Quotation") + sqi = frappe.qb.DocType("Supplier Quotation Item") + existing_quotation = ( + frappe.qb.from_(sq) + .inner_join(sqi) + .on(sq.name == sqi.parent) + .select(sq.name, sqi.request_for_quotation) + .where( + (sq.docstatus < 2) + & (sq.supplier == supplier) + & (sqi.request_for_quotation.isin(request_for_quotations)) + ) + .limit(1) + ).run(as_dict=True) + + if existing_quotation: + existing_quotation = existing_quotation[0] + frappe.throw( + _("Supplier Quotation {0} already exists against Request for Quotation {1}").format( + frappe.bold(existing_quotation.name), + frappe.bold(existing_quotation.request_for_quotation), + ) ) - add_items(sq_doc, doc.get("supplier"), doc.get("items")) - sq_doc.flags.ignore_permissions = True - sq_doc.run_method("set_missing_values") - sq_doc.save() - frappe.msgprint(_("Supplier Quotation {0} Created").format(sq_doc.name)) - return sq_doc.name - except Exception: - return None def add_items(sq_doc, supplier, items): diff --git a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py index a92d8d95626..1727fb9835e 100644 --- a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py +++ b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py @@ -17,6 +17,7 @@ from erpnext.buying.doctype.request_for_quotation.request_for_quotation import ( from erpnext.controllers.accounts_controller import InvalidQtyError from erpnext.crm.doctype.opportunity.opportunity import make_request_for_quotation as make_rfq from erpnext.crm.doctype.opportunity.test_opportunity import make_opportunity +from erpnext.exceptions import PartyDisabled from erpnext.stock.doctype.item.test_item import make_item from erpnext.templates.pages.rfq import check_supplier_has_docname_access @@ -57,6 +58,17 @@ class TestRequestforQuotation(FrappeTestCase): self.assertEqual(rfq.get("suppliers")[0].quote_status, "Received") self.assertEqual(rfq.get("suppliers")[1].quote_status, "Pending") + def test_rfq_blocked_for_disabled_supplier(self): + frappe.db.set_value("Supplier", "_Test Supplier", "disabled", 1) + rfq = make_request_for_quotation( + supplier_data=[{"supplier": "_Test Supplier", "supplier_name": "_Test Supplier"}], + do_not_save=True, + ) + self.assertRaises(PartyDisabled, rfq.save) + + frappe.db.set_value("Supplier", "_Test Supplier", "disabled", 0) + rfq.save() + def test_make_supplier_quotation(self): rfq = make_request_for_quotation() @@ -149,6 +161,18 @@ class TestRequestforQuotation(FrappeTestCase): self.assertEqual(supplier_quotation_doc.get("items")[0].qty, 5) self.assertEqual(supplier_quotation_doc.get("items")[0].amount, 500) + def test_make_duplicate_supplier_quotation_from_portal(self): + rfq = make_request_for_quotation() + rfq.supplier = rfq.suppliers[0].supplier + supplier_quotation = frappe.get_doc("Supplier Quotation", create_supplier_quotation(rfq)) + supplier_quotation.submit() + + with self.assertRaisesRegex(frappe.ValidationError, "already exists"): + create_supplier_quotation(rfq) + + supplier_quotation.cancel() + self.assertTrue(create_supplier_quotation(rfq)) + def test_make_multi_uom_supplier_quotation(self): item_code = "_Test Multi UOM RFQ Item" if not frappe.db.exists("Item", item_code): diff --git a/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.json b/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.json index 69d530da7ee..5862b8cde18 100644 --- a/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.json +++ b/erpnext/buying/doctype/request_for_quotation_supplier/request_for_quotation_supplier.json @@ -40,6 +40,7 @@ "fieldtype": "Link", "in_list_view": 1, "label": "Supplier", + "link_filters": "[[\"Supplier\",\"disabled\",\"=\",0]]", "options": "Supplier", "reqd": 1 }, diff --git a/erpnext/buying/doctype/supplier/test_supplier.py b/erpnext/buying/doctype/supplier/test_supplier.py index e0a2a379ed8..69c81eb2e80 100644 --- a/erpnext/buying/doctype/supplier/test_supplier.py +++ b/erpnext/buying/doctype/supplier/test_supplier.py @@ -125,12 +125,12 @@ class TestSupplier(FrappeTestCase): self.assertEqual(supplier.country, "Greece") def test_party_details_tax_category(self): - from erpnext.accounts.party import get_party_details + from erpnext.accounts.party import _get_party_details frappe.delete_doc_if_exists("Address", "_Test Address With Tax Category-Billing") # Tax Category without Address - details = get_party_details("_Test Supplier With Tax Category", party_type="Supplier") + details = _get_party_details("_Test Supplier With Tax Category", party_type="Supplier") self.assertEqual(details.tax_category, "_Test Tax Category 1") address = frappe.get_doc( @@ -147,7 +147,7 @@ class TestSupplier(FrappeTestCase): ).insert() # Tax Category with Address - details = get_party_details("_Test Supplier With Tax Category", party_type="Supplier") + details = _get_party_details("_Test Supplier With Tax Category", party_type="Supplier") self.assertEqual(details.tax_category, "_Test Tax Category 2") # Rollback diff --git a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.js b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.js index 0df7e0787a9..5073459636e 100644 --- a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.js +++ b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.js @@ -85,6 +85,17 @@ frappe.query_reports["Supplier Quotation Comparison"] = { ], default: __("Categorize by Supplier"), }, + { + fieldname: "status", + label: __("Status"), + fieldtype: "Select", + options: [ + { label: "", value: "" }, + { label: __("Draft"), value: "Draft" }, + { label: __("Submitted"), value: "Submitted" }, + ], + default: "Submitted", + }, { fieldtype: "Check", label: __("Include Expired"), diff --git a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py index 7c11dda7225..47ce00fa692 100644 --- a/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py +++ b/erpnext/buying/report/supplier_quotation_comparison/supplier_quotation_comparison.py @@ -58,13 +58,20 @@ def get_data(filters): ) .where( (sq_item.parent == sq.name) - & (sq_item.docstatus < 2) & (sq.company == filters.get("company")) & (sq.transaction_date.between(filters.get("from_date"), filters.get("to_date"))) ) .orderby(sq.transaction_date, sq_item.item_code) ) + # blank -> Draft + Submitted, else filter to the chosen docstatus + if filters.get("status") == "Draft": + query = query.where(sq_item.docstatus == 0) + elif filters.get("status") == "Submitted": + query = query.where(sq_item.docstatus == 1) + else: + query = query.where(sq_item.docstatus < 2) + if filters.get("item_code"): query = query.where(sq_item.item_code == filters.get("item_code")) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index c19d254b56c..74325b7c0bc 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -67,6 +67,7 @@ from erpnext.setup.utils import get_exchange_rate from erpnext.stock.doctype.item.item import get_uom_conv_factor from erpnext.stock.doctype.packed_item.packed_item import make_packing_list from erpnext.stock.get_item_details import ( + NOT_APPLICABLE_TAX, _get_item_tax_template, _get_item_tax_template_from_item_group, get_bin_details, @@ -719,6 +720,8 @@ class AccountsController(TransactionBase): self.validate_non_invoice_documents_schedule() def before_print(self, settings=None): + self.set_missing_terms() + if self.doctype in [ "Purchase Order", "Sales Order", @@ -742,6 +745,16 @@ class AccountsController(TransactionBase): set_print_templates_for_item_table(self, settings) set_print_templates_for_taxes(self, settings) + def set_missing_terms(self): + if not self.get("tc_name") or self.get("terms"): + return + + from erpnext.setup.doctype.terms_and_conditions.terms_and_conditions import ( + get_terms_and_conditions, + ) + + self.terms = get_terms_and_conditions(self.tc_name, self.as_dict()) + def calculate_paid_amount(self): if hasattr(self, "is_pos") or hasattr(self, "is_paid"): is_paid = self.get("is_pos") or self.get("is_paid") @@ -1282,7 +1295,10 @@ class AccountsController(TransactionBase): if isinstance(item_tax_rate, str): item_tax_rate = parse_json(item_tax_rate) - for account_head, _rate in item_tax_rate.items(): + for account_head, rate in item_tax_rate.items(): + if rate == NOT_APPLICABLE_TAX: + continue + row = self.get_tax_row(account_head) if not row: @@ -3709,8 +3725,11 @@ def add_taxes_from_tax_template(child_item, parent_doc, db_insert=True): if child_item.get("item_tax_rate") and add_taxes_from_item_tax_template: tax_map = json.loads(child_item.get("item_tax_rate")) - for tax_type in tax_map: - tax_rate = flt(tax_map[tax_type]) + for tax_type, tax_rate in tax_map.items(): + if tax_rate == NOT_APPLICABLE_TAX: + continue + + tax_rate = flt(tax_rate) taxes = parent_doc.get("taxes") or [] # add new row for tax head only if missing found = any(tax.account_head == tax_type for tax in taxes) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 5b8df2cf767..a4323365201 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -11,7 +11,7 @@ from frappe.utils.data import nowtime import erpnext from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_dimensions from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget -from erpnext.accounts.party import get_party_details +from erpnext.accounts.party import _get_party_details from erpnext.buying.utils import update_last_purchase_rate, validate_for_items from erpnext.controllers.accounts_controller import get_taxes_and_charges from erpnext.controllers.sales_and_purchase_return import get_rate_for_return @@ -165,7 +165,7 @@ class BuyingController(SubcontractingController): # set contact and address details for supplier, if they are not mentioned if getattr(self, "supplier", None): self.update_if_missing( - get_party_details( + _get_party_details( self.supplier, party_type="Supplier", doctype=self.doctype, @@ -755,7 +755,7 @@ class BuyingController(SubcontractingController): if po and po_item_rows: po_obj = frappe.get_doc("Purchase Order", po) - if po_obj.status in ["Closed", "Cancelled"]: + if po_obj.status == "Cancelled" or (po_obj.status == "Closed" and not self.get("is_return")): frappe.throw( _("{0} {1} is cancelled or closed").format(_("Purchase Order"), po), frappe.InvalidStatusError, diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index b5cc37e48fa..4d348112446 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -213,7 +213,7 @@ def validate_quantity(doc, key, args, ref, valid_items, already_returned_items): else 0 ) - if column == "stock_qty" and not args.get("return_qty_from_rejected_warehouse"): + if column in ("stock_qty", "qty") and not args.get("return_qty_from_rejected_warehouse"): reference_qty = ref.get(column) current_stock_qty = args.get(column) elif args.get("return_qty_from_rejected_warehouse"): diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index f1e3baebc51..fd5b564b6b0 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -560,7 +560,8 @@ class SellingController(StockController): reset_incoming_rate() if ( - not d.incoming_rate + (not d.incoming_rate or self.is_new()) + and not is_standalone or self.is_internal_transfer() or (get_valuation_method(d.item_code) == "Moving Average" and self.get("is_return")) ): diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index a8a48140bdd..33d253ddc14 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -19,7 +19,11 @@ from erpnext.controllers.accounts_controller import ( validate_inclusive_tax, validate_taxes_and_charges, ) -from erpnext.stock.get_item_details import _get_item_tax_template, get_item_tax_map +from erpnext.stock.get_item_details import ( + NOT_APPLICABLE_TAX, + _get_item_tax_template, + get_item_tax_map, +) from erpnext.utilities.regional import temporary_flag @@ -275,6 +279,7 @@ class calculate_taxes_and_totals: tax.item_wise_tax_detail = {} tax_fields = [ + "net_amount", "total", "tax_amount_after_discount_amount", "tax_amount_for_current_item", @@ -298,33 +303,32 @@ class calculate_taxes_and_totals: for item in self.doc.items: item_tax_map = self._load_item_tax_rate(item.item_tax_rate) - cumulated_tax_fraction = 0 - total_inclusive_tax_amount_per_qty = 0 + total_tax_slope = 0 + total_tax_intercept = 0 for i, tax in enumerate(self.doc.get("taxes")): ( tax.tax_fraction_for_current_item, - inclusive_tax_amount_per_qty, - ) = self.get_current_tax_fraction(tax, item_tax_map) + tax_intercept_per_qty, + ) = self.get_current_tax_fraction(tax, item_tax_map, item) + tax.inclusive_amount_per_qty = tax_intercept_per_qty if i == 0: tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item + tax.grand_total_amount_per_qty = tax_intercept_per_qty else: + prev = self.doc.get("taxes")[i - 1] tax.grand_total_fraction_for_current_item = ( - self.doc.get("taxes")[i - 1].grand_total_fraction_for_current_item - + tax.tax_fraction_for_current_item + prev.grand_total_fraction_for_current_item + tax.tax_fraction_for_current_item ) + tax.grand_total_amount_per_qty = prev.grand_total_amount_per_qty + tax_intercept_per_qty - cumulated_tax_fraction += tax.tax_fraction_for_current_item - total_inclusive_tax_amount_per_qty += inclusive_tax_amount_per_qty * flt(item.qty) + total_tax_slope += tax.tax_fraction_for_current_item + total_tax_intercept += tax_intercept_per_qty * flt(item.qty) - if ( - not self.discount_amount_applied - and item.qty - and (cumulated_tax_fraction or total_inclusive_tax_amount_per_qty) - ): - amount = flt(item.amount) - total_inclusive_tax_amount_per_qty + if not self.discount_amount_applied and item.qty and (total_tax_slope or total_tax_intercept): + amount = flt(item.amount) - total_tax_intercept - item.net_amount = flt(amount / (1 + cumulated_tax_fraction), item.precision("net_amount")) + item.net_amount = flt(amount / (1 + total_tax_slope), item.precision("net_amount")) item.net_rate = flt(item.net_amount / item.qty, item.precision("net_rate")) item.discount_percentage = flt( item.discount_percentage, item.precision("discount_percentage") @@ -335,44 +339,57 @@ class calculate_taxes_and_totals: def _load_item_tax_rate(self, item_tax_rate): return json.loads(item_tax_rate) if item_tax_rate else {} - def get_current_tax_fraction(self, tax, item_tax_map): + def get_current_tax_fraction(self, tax, item_tax_map, item): """ - Get tax fraction for calculating tax exclusive amount - from tax inclusive amount + tax = slope * net + intercept. + Returns (slope, intercept_per_qty) """ - current_tax_fraction = 0 - inclusive_tax_amount_per_qty = 0 + tax_slope = 0 + tax_intercept = 0 if cint(tax.included_in_print_rate): tax_rate = self._get_tax_rate(tax, item_tax_map) + if tax_rate == NOT_APPLICABLE_TAX: + return tax_slope, tax_intercept + if tax.charge_type == "On Net Total": - current_tax_fraction = tax_rate / 100.0 + tax_slope = tax_rate / 100.0 elif tax.charge_type == "On Previous Row Amount": - current_tax_fraction = (tax_rate / 100.0) * self.doc.get("taxes")[ - cint(tax.row_id) - 1 - ].tax_fraction_for_current_item + row = self.doc.get("taxes")[cint(tax.row_id) - 1] + tax_slope = (tax_rate / 100.0) * row.tax_fraction_for_current_item + tax_intercept = (tax_rate / 100.0) * flt(getattr(row, "inclusive_amount_per_qty", 0)) elif tax.charge_type == "On Previous Row Total": - current_tax_fraction = (tax_rate / 100.0) * self.doc.get("taxes")[ - cint(tax.row_id) - 1 - ].grand_total_fraction_for_current_item + row = self.doc.get("taxes")[cint(tax.row_id) - 1] + tax_slope = (tax_rate / 100.0) * row.grand_total_fraction_for_current_item + tax_intercept = (tax_rate / 100.0) * flt(getattr(row, "grand_total_amount_per_qty", 0)) elif tax.charge_type == "On Item Quantity": - inclusive_tax_amount_per_qty = flt(tax_rate) + tax_intercept = flt(tax_rate) + + else: + # Custom charge_type: the rate applies to a resolved (fixed) base, + # e.g. a tax on MRP included in the printed price. + qty = flt(item.qty) or 1 + base = self.get_item_taxable_base(item, tax) + tax_intercept = (tax_rate / 100.0) * base / qty if getattr(tax, "add_deduct_tax", None) and tax.add_deduct_tax == "Deduct": - current_tax_fraction *= -1.0 - inclusive_tax_amount_per_qty *= -1.0 + tax_slope *= -1.0 + tax_intercept *= -1.0 - return current_tax_fraction, inclusive_tax_amount_per_qty + return tax_slope, tax_intercept def _get_tax_rate(self, tax, item_tax_map): if tax.account_head in item_tax_map: - return flt(item_tax_map.get(tax.account_head), self.doc.precision("rate", tax)) - else: - return tax.rate + rate = item_tax_map[tax.account_head] + if rate == NOT_APPLICABLE_TAX: + return NOT_APPLICABLE_TAX + return flt(rate, self.doc.precision("rate", tax)) + + return tax.rate def calculate_net_total(self): self.doc.total_qty = ( @@ -420,9 +437,12 @@ class calculate_taxes_and_totals: item_tax_map = self._load_item_tax_rate(item.item_tax_rate) for i, tax in enumerate(doc.taxes): # tax_amount represents the amount of tax for the current step - current_tax_amount = self.get_current_tax_amount(item, tax, item_tax_map) + current_net_amount, current_tax_amount = self.get_current_tax_and_net_amount( + item, tax, item_tax_map + ) if frappe.flags.round_row_wise_tax: current_tax_amount = flt(current_tax_amount, tax.precision("tax_amount")) + current_net_amount = flt(current_net_amount, tax.precision("net_amount")) # Adjust divisional loss to the last item if tax.charge_type == "Actual": @@ -430,6 +450,10 @@ class calculate_taxes_and_totals: if n == len(self._items) - 1: current_tax_amount += actual_tax_dict[tax.idx] + # net_amount is the taxable basis, it feeds no total and is always + # accumulated, unlike tax_amount which is kept from the first pass + tax.net_amount += current_net_amount + # accumulate tax amount into tax.tax_amount if tax.charge_type != "Actual" and not ( self.discount_amount_applied and self.doc.apply_discount_on == "Grand Total" @@ -480,7 +504,9 @@ class calculate_taxes_and_totals: for i, tax in enumerate(doc.taxes): self.round_off_totals(tax) - self._set_in_company_currency(tax, ["tax_amount", "tax_amount_after_discount_amount"]) + self._set_in_company_currency( + tax, ["tax_amount", "tax_amount_after_discount_amount", "net_amount"] + ) self.round_off_base_values(tax) self.set_cumulative_total(i, tax) @@ -511,8 +537,17 @@ class calculate_taxes_and_totals: tax.total = flt(self.doc.get("taxes")[row_idx - 1].total + tax_amount, tax.precision("total")) def get_current_tax_amount(self, item, tax, item_tax_map): + # kept for backwards compatibility with callers outside this module + _, current_tax_amount = self.get_current_tax_and_net_amount(item, tax, item_tax_map) + return current_tax_amount + + def get_current_tax_and_net_amount(self, item, tax, item_tax_map): tax_rate = self._get_tax_rate(tax, item_tax_map) current_tax_amount = 0.0 + current_net_amount = 0.0 + + if tax_rate == NOT_APPLICABLE_TAX: + return current_net_amount, current_tax_amount if tax.charge_type == "Actual": # distribute the tax amount proportionally to each item row @@ -522,29 +557,63 @@ class calculate_taxes_and_totals: if not item.get("apply_tds") or not self.doc.tax_withholding_net_total: current_tax_amount = 0.0 else: - current_tax_amount = item.net_amount * actual / self.doc.tax_withholding_net_total + current_net_amount = item.net_amount + current_tax_amount = current_net_amount * actual / self.doc.tax_withholding_net_total else: + current_net_amount = item.net_amount current_tax_amount = ( - item.net_amount * actual / self.doc.net_total if self.doc.net_total else 0.0 + current_net_amount * actual / self.doc.net_total if self.doc.net_total else 0.0 ) elif tax.charge_type == "On Net Total": + current_net_amount = item.net_amount current_tax_amount = (tax_rate / 100.0) * item.net_amount elif tax.charge_type == "On Previous Row Amount": - current_tax_amount = (tax_rate / 100.0) * self.doc.get("taxes")[ - cint(tax.row_id) - 1 - ].tax_amount_for_current_item + current_net_amount = self.doc.get("taxes")[cint(tax.row_id) - 1].tax_amount_for_current_item + current_tax_amount = (tax_rate / 100.0) * current_net_amount elif tax.charge_type == "On Previous Row Total": - current_tax_amount = (tax_rate / 100.0) * self.doc.get("taxes")[ - cint(tax.row_id) - 1 - ].grand_total_for_current_item + current_net_amount = self.doc.get("taxes")[cint(tax.row_id) - 1].grand_total_for_current_item + current_tax_amount = (tax_rate / 100.0) * current_net_amount elif tax.charge_type == "On Item Quantity": + # don't sum current net amount: net_amount field is currency-denominated current_tax_amount = tax_rate * item.qty + else: + # Custom charge_type: rate applies to the resolver-provided base. + current_tax_amount = (tax_rate / 100.0) * self.get_item_taxable_base(item, tax) if not (self.doc.get("is_consolidated") or tax.get("dont_recompute_tax")): self.set_item_wise_tax(item, tax, tax_rate, current_tax_amount) - return current_tax_amount + return current_net_amount, current_tax_amount + + def get_item_taxable_base(self, item, tax): + """Per-item base a custom charge_type's rate is applied to. + + Override the base (gross, MRP, net of other taxes, …) via the + `erpnext_taxable_base_resolvers` hook + + Register a resolver in `hooks.py`, keyed by charge_type: + + erpnext_taxable_base_resolvers = {"On Gross Amount": "my_app.taxes.gross_base"} + + It receives (calc, item, tax) — calc is this instance, calc.doc the parent — + and returns the base (flt-coerced by the caller): + + def gross_base(calc, item, tax): + return item.custom_field_mrp * item.qty + + A resolver may stamp transient attributes on `item`; it can be called more than once + per item, so such stamping must be idempotent. + """ + resolvers = frappe.get_hooks("erpnext_taxable_base_resolvers") or {} + path = resolvers.get(tax.charge_type) + + if path: + method = path[-1] if isinstance(path, list | tuple) else path + return flt(frappe.get_attr(method)(self, item, tax)) + + # fallback + return flt(item.net_amount) def set_item_wise_tax(self, item, tax, tax_rate, current_tax_amount): # store tax breakup for each item @@ -788,8 +857,9 @@ class calculate_taxes_and_totals: item.net_amount = flt( item.net_amount + rounding_difference, item.precision("net_amount") ) + # net_amount went up by rounding_difference, so its discount share goes down item.distributed_discount_amount = flt( - distributed_amount + rounding_difference, + distributed_amount - rounding_difference, item.precision("distributed_discount_amount"), ) net_total += rounding_difference diff --git a/erpnext/controllers/tests/test_distributed_discount.py b/erpnext/controllers/tests/test_distributed_discount.py index 74ae69c1750..d87ea1b07b0 100644 --- a/erpnext/controllers/tests/test_distributed_discount.py +++ b/erpnext/controllers/tests/test_distributed_discount.py @@ -1,4 +1,4 @@ -from frappe.tests.utils import FrappeTestCase +from frappe.tests.utils import FrappeTestCase, change_settings from erpnext.accounts.test.accounts_mixin import AccountsTestMixin from erpnext.controllers.taxes_and_totals import calculate_taxes_and_totals @@ -60,6 +60,30 @@ class TestTaxesAndTotals(AccountsTestMixin, FrappeTestCase): self.assertAlmostEqual(so.net_total, 1272.73, places=2) self.assertEqual(so.grand_total, 1400) + @change_settings("Selling Settings", {"allow_multiple_items": 1}) + def test_distributed_discount_amount_with_rounding_adjustment(self): + so = make_sales_order(do_not_save=1) + so.apply_discount_on = "Net Total" + so.discount_amount = 10 + so.items[0].qty = 1 + so.items[0].rate = 100 + so.append("items", so.items[0].as_dict()) + so.append("items", so.items[0].as_dict()) + so.save() + + calculate_taxes_and_totals(so) + + # the rounding adjustment lands on the second line + self.assertAlmostEqual(so.items[1].net_amount, 96.66, places=2) + self.assertAlmostEqual(so.items[1].distributed_discount_amount, 3.34, places=2) + + for item in so.items: + self.assertAlmostEqual(item.amount - item.distributed_discount_amount, item.net_amount, places=2) + self.assertAlmostEqual( + sum(i.distributed_discount_amount for i in so.items), so.discount_amount, places=2 + ) + self.assertEqual(so.net_total, 290) + def test_100_percent_discount_with_inclusive_tax(self): """Test that 100% discount with inclusive taxes results in zero net_total""" so = make_sales_order(do_not_save=1) diff --git a/erpnext/controllers/tests/test_sales_and_purchase_return.py b/erpnext/controllers/tests/test_sales_and_purchase_return.py index 0de679352f7..cd21d321776 100644 --- a/erpnext/controllers/tests/test_sales_and_purchase_return.py +++ b/erpnext/controllers/tests/test_sales_and_purchase_return.py @@ -87,3 +87,35 @@ class TestSalesAndPurchaseReturn(FrappeTestCase): return_si.items[0].qty = 0 self.assertRaises(frappe.ValidationError, return_si.save) + + def test_sales_invoice_partial_return_with_different_stock_uom(self): + from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice + from erpnext.controllers.sales_and_purchase_return import make_return_doc + from erpnext.stock.doctype.item.test_item import make_item + + item_properties = {"is_stock_item": 1, "stock_uom": "Kg"} + if frappe.get_meta("Item").has_field("gst_hsn_code") and frappe.db.exists("GST HSN Code", "010121"): + item_properties["gst_hsn_code"] = "010121" + + item = make_item( + "_Test SI Return Different Stock UOM", + item_properties, + uoms=[{"uom": "Nos", "conversion_factor": 0.013888889}], + ) + + si = create_sales_invoice(item_code=item.name, qty=48, do_not_save=True) + si.items[0].uom = "Nos" + si.items[0].stock_uom = "Kg" + si.items[0].conversion_factor = 0.013888889 + si.save().submit() + self.addCleanup(self._cancel_and_delete, "Sales Invoice", si.name) + + first_return = make_return_doc(si.doctype, si.name) + first_return.items[0].qty = -24 + first_return.save().submit() + self.addCleanup(self._cancel_and_delete, "Sales Invoice", first_return.name) + + second_return = make_return_doc(si.doctype, si.name) + self.assertEqual(second_return.items[0].qty, -24) + second_return.save().submit() + self.addCleanup(self._cancel_and_delete, "Sales Invoice", second_return.name) diff --git a/erpnext/controllers/tests/test_taxes_and_totals.py b/erpnext/controllers/tests/test_taxes_and_totals.py index 715acf8782f..481651c0cce 100644 --- a/erpnext/controllers/tests/test_taxes_and_totals.py +++ b/erpnext/controllers/tests/test_taxes_and_totals.py @@ -1,12 +1,24 @@ +from unittest import mock from unittest.mock import patch import frappe from frappe.tests.utils import FrappeTestCase +from frappe.utils import flt from erpnext.controllers.taxes_and_totals import calculate_taxes_and_totals from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order +def resolve_on_gross(calc, item, tax): + # base = gross printed line amount + return flt(item.amount) + + +def resolve_on_mrp(calc, item, tax): + # base = MRP, not net + return flt(item.price_list_rate) * flt(item.qty) + + class TestTaxesAndTotals(FrappeTestCase): def test_regional_round_off_accounts(self): """ @@ -30,6 +42,93 @@ class TestTaxesAndTotals(FrappeTestCase): self.assertIn(test_account, frappe.flags.round_off_applicable_accounts) + def test_exclusive_custom_charge_on_resolved_base(self): + """Added (exclusive) custom charge_type whose base is resolved by the + `erpnext_taxable_base_resolvers` hook. IPI 10% on the gross product value 1000 + -> tax 100, net 1000, grand 1100.""" + so = make_sales_order(do_not_save=True) + so.items = [] + so.append( + "items", + { + "item_code": "_Test Item", + "qty": 1, + "rate": 1000, + "price_list_rate": 1000, + "warehouse": "_Test Warehouse - _TC", + }, + ) + so.set("taxes", []) + so.append( + "taxes", + { + "charge_type": "On Gross Value", + "account_head": "_Test Account Excise Duty - _TC", + "description": "IPI 10% on gross product value", + "rate": 10, + "cost_center": "_Test Cost Center - _TC", + }, + ) + + real_get_hooks = frappe.get_hooks + + def fake_get_hooks(hook=None, *args, **kwargs): + if hook == "erpnext_taxable_base_resolvers": + return { + "On Gross Value": ["erpnext.controllers.tests.test_taxes_and_totals.resolve_on_gross"] + } + return real_get_hooks(hook, *args, **kwargs) + + with mock.patch("frappe.get_hooks", side_effect=fake_get_hooks): + calculate_taxes_and_totals(so) + + self.assertEqual(so.net_total, 1000.0) + self.assertEqual(so.taxes[0].tax_amount, 100.0) + self.assertEqual(so.grand_total, 1100.0) + + def test_inclusive_custom_charge_on_resolved_base(self): + """Inclusive custom charge on a resolved base backs out non-compounding + (tax = rate x resolved base) — a resolved base is fixed, so it never + compounds. MRP 1200, printed 1000, rate 10%: tax 120, net 880.""" + so = make_sales_order(do_not_save=True) + so.items = [] + so.append( + "items", + { + "item_code": "_Test Item", + "qty": 1, + "rate": 1000, + "price_list_rate": 1200, + "warehouse": "_Test Warehouse - _TC", + }, + ) + so.set("taxes", []) + so.append( + "taxes", + { + "charge_type": "On MRP", + "account_head": "_Test Account VAT - _TC", + "description": "Tax 10% on MRP, inclusive", + "rate": 10, + "included_in_print_rate": 1, + "cost_center": "_Test Cost Center - _TC", + }, + ) + + real_get_hooks = frappe.get_hooks + + def fake_get_hooks(hook=None, *args, **kwargs): + if hook == "erpnext_taxable_base_resolvers": + return {"On MRP": ["erpnext.controllers.tests.test_taxes_and_totals.resolve_on_mrp"]} + return real_get_hooks(hook, *args, **kwargs) + + with mock.patch("frappe.get_hooks", side_effect=fake_get_hooks): + calculate_taxes_and_totals(so) + + self.assertEqual(so.taxes[0].tax_amount, 120.0) + self.assertEqual(so.net_total, 880.0) + self.assertEqual(so.grand_total, 1000.0) + def test_disabling_rounded_total_resets_base_fields(self): """Disabling rounded total should also clear base rounded values.""" so = make_sales_order(do_not_save=True) @@ -59,3 +158,141 @@ class TestTaxesAndTotals(FrappeTestCase): self.assertEqual(so.rounding_adjustment, 0) self.assertEqual(so.base_rounded_total, 0) self.assertEqual(so.base_rounding_adjustment, 0) + + def test_tax_net_amount_with_not_applicable_item_tax(self): + """Each tax row records only the net of the items it actually applies to. + + Two items of 100 each, one per template. Template A applies VAT 7 and + marks VAT 19 not applicable, template B does the reverse. Both tax rows + must report a net_amount of 100, not the full net total of 200. + """ + vat_7 = "_Test Account VAT - _TC" + vat_19 = "_Test Account Service Tax - _TC" + + templates = {} + for title, rows in { + "_Test NA Template A": [(vat_7, 7, 0), (vat_19, 0, 1)], + "_Test NA Template B": [(vat_7, 0, 1), (vat_19, 19, 0)], + }.items(): + doc = frappe.new_doc("Item Tax Template") + doc.title = title + doc.company = "_Test Company" + for tax_type, tax_rate, not_applicable in rows: + doc.append( + "taxes", + {"tax_type": tax_type, "tax_rate": tax_rate, "not_applicable": not_applicable}, + ) + templates[title] = doc.insert().name + + so = make_sales_order(do_not_save=True) + so.items = [] + for title in templates: + so.append( + "items", + { + "item_code": "_Test Item", + "qty": 1, + "rate": 100, + "warehouse": "_Test Warehouse - _TC", + "item_tax_template": templates[title], + }, + ) + + so.set("taxes", []) + for account_head in (vat_7, vat_19): + so.append( + "taxes", + { + "charge_type": "On Net Total", + "account_head": account_head, + "description": account_head, + "rate": 0, + "cost_center": "_Test Cost Center - _TC", + }, + ) + + so.save() + + self.assertEqual(so.net_total, 200.0) + self.assertEqual(so.taxes[0].net_amount, 100.0) + self.assertEqual(so.taxes[0].tax_amount, 7.0) + self.assertEqual(so.taxes[1].net_amount, 100.0) + self.assertEqual(so.taxes[1].tax_amount, 19.0) + + def test_inclusive_tax_with_not_applicable_item_tax(self): + """An inclusive tax row meeting an item that marks it not applicable must + contribute no fraction, instead of raising in get_current_tax_fraction.""" + vat_19 = "_Test Account Service Tax - _TC" + + template = frappe.new_doc("Item Tax Template") + template.title = "_Test NA Template Inclusive" + template.company = "_Test Company" + template.append("taxes", {"tax_type": vat_19, "tax_rate": 0, "not_applicable": 1}) + template.insert() + + so = make_sales_order(do_not_save=True) + so.items = [] + so.append( + "items", + { + "item_code": "_Test Item", + "qty": 1, + "rate": 119, + "warehouse": "_Test Warehouse - _TC", + "item_tax_template": template.name, + }, + ) + so.set("taxes", []) + so.append( + "taxes", + { + "charge_type": "On Net Total", + "account_head": vat_19, + "description": vat_19, + "rate": 19, + "included_in_print_rate": 1, + "cost_center": "_Test Cost Center - _TC", + }, + ) + + so.save() + + # the tax does not apply, so nothing is backed out of the printed rate + self.assertEqual(so.net_total, 119.0) + self.assertEqual(so.taxes[0].tax_amount, 0.0) + self.assertEqual(so.taxes[0].net_amount, 0.0) + self.assertEqual(so.grand_total, 119.0) + + def test_tax_net_amount_survives_grand_total_discount(self): + """A discount on Grand Total re-runs the calculation with + discount_amount_applied set. net_amount is reset on that second pass, so + it has to be accumulated there too instead of being left at zero.""" + so = make_sales_order(do_not_save=True) + so.items = [] + so.append( + "items", + { + "item_code": "_Test Item", + "qty": 10, + "rate": 100, + "warehouse": "_Test Warehouse - _TC", + }, + ) + so.set("taxes", []) + so.append( + "taxes", + { + "charge_type": "On Net Total", + "account_head": "_Test Account VAT - _TC", + "description": "VAT", + "rate": 19, + "cost_center": "_Test Cost Center - _TC", + }, + ) + so.apply_discount_on = "Grand Total" + so.discount_amount = 100 + + calculate_taxes_and_totals(so) + + self.assertEqual(so.taxes[0].net_amount, so.net_total) + self.assertEqual(so.grand_total, 1090.0) diff --git a/erpnext/crm/doctype/crm_settings/crm_settings.py b/erpnext/crm/doctype/crm_settings/crm_settings.py index 379c55ae5b3..73c0156e291 100644 --- a/erpnext/crm/doctype/crm_settings/crm_settings.py +++ b/erpnext/crm/doctype/crm_settings/crm_settings.py @@ -69,6 +69,13 @@ class CRMSettings(Document): self.allowed_users = [] def custom_fields_for_frappe_crm_data_sync(self): + custom_fields = self.get_frappe_crm_custom_fields() + + if self.enable_frappe_crm_data_synchronization: + create_custom_fields(custom_fields, ignore_validate=True) + + @staticmethod + def get_frappe_crm_custom_fields(): custom_fields = { "Quotation": [ { @@ -88,4 +95,4 @@ class CRMSettings(Document): ], } - create_custom_fields(custom_fields, ignore_validate=True) + return custom_fields diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py index aa8d75e1826..c8db39103f3 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.py +++ b/erpnext/crm/doctype/opportunity/opportunity.py @@ -13,6 +13,7 @@ from frappe.query_builder import DocType, Interval from frappe.query_builder.functions import Now from frappe.utils import flt, get_fullname +from erpnext.accounts.party import validate_party_frozen_disabled from erpnext.crm.utils import ( CRMNote, copy_comments, @@ -131,6 +132,7 @@ class Opportunity(TransactionBase, CRMNote): self.validate_item_details() self.validate_uom_is_integer("uom", "qty") self.validate_cust_name() + self.validate_party() self.map_fields() self.validate_qty() self.set_exchange_rate() @@ -346,6 +348,10 @@ class Opportunity(TransactionBase, CRMNote): return False return True + def validate_party(self) -> None: + if self.opportunity_from == "Customer": + validate_party_frozen_disabled("Customer", self.party_name) + def validate_cust_name(self): if self.party_name: if self.opportunity_from == "Customer": diff --git a/erpnext/crm/doctype/opportunity/test_opportunity.py b/erpnext/crm/doctype/opportunity/test_opportunity.py index f346946568e..2179e35bf7e 100644 --- a/erpnext/crm/doctype/opportunity/test_opportunity.py +++ b/erpnext/crm/doctype/opportunity/test_opportunity.py @@ -10,6 +10,7 @@ from erpnext.crm.doctype.lead.lead import make_customer from erpnext.crm.doctype.lead.test_lead import make_lead from erpnext.crm.doctype.opportunity.opportunity import make_quotation from erpnext.crm.utils import get_linked_communication_list +from erpnext.exceptions import PartyDisabled test_records = frappe.get_test_records("Opportunity") @@ -52,6 +53,23 @@ class TestOpportunity(unittest.TestCase): opportunity_doc = make_opportunity(with_items=1, rate=1100, qty=2) self.assertEqual(opportunity_doc.total, 2200) + def test_disabled_customer_not_allowed(self): + frappe.db.set_value("Customer", "_Test Customer", "disabled", 1) + + self.assertRaises(PartyDisabled, make_opportunity, with_items=0) + + frappe.db.set_value("Customer", "_Test Customer", "disabled", 0) + make_opportunity(with_items=0) + + def test_disabled_lead_not_blocked(self): + # Lead.disabled isn't enforced anywhere else (e.g. the Lead picker query only + # excludes Converted leads), so it shouldn't block Opportunity creation either. + lead_doc = make_lead() + frappe.db.set_value("Lead", lead_doc.name, "disabled", 1) + + opp_doc = make_opportunity(opportunity_from="Lead", lead=lead_doc.name) + self.assertEqual(opp_doc.party_name, lead_doc.name) + def test_carry_forward_of_email_and_comments(self): frappe.db.set_single_value("CRM Settings", "carry_forward_communication_and_comments", 1) lead_doc = make_lead() diff --git a/erpnext/crm/doctype/utils.py b/erpnext/crm/doctype/utils.py index cacc5a16607..f3230e36568 100644 --- a/erpnext/crm/doctype/utils.py +++ b/erpnext/crm/doctype/utils.py @@ -1,53 +1,6 @@ import frappe -@frappe.whitelist() -def get_last_interaction(contact=None, lead=None): - if not contact and not lead: - return - - last_communication = None - last_issue = None - if contact: - query_condition = "" - values = [] - contact = frappe.get_doc("Contact", contact) - for link in contact.links: - if link.link_doctype == "Customer": - last_issue = get_last_issue_from_customer(link.link_name) - query_condition += "(`reference_doctype`=%s AND `reference_name`=%s) OR" - values += [link.link_doctype, link.link_name] - - if query_condition: - # remove extra appended 'OR' - query_condition = query_condition[:-2] - last_communication = frappe.db.sql( - f""" - SELECT `name`, `content` - FROM `tabCommunication` - WHERE `sent_or_received`='Received' - AND ({query_condition}) - ORDER BY `modified` - LIMIT 1 - """, - values, - as_dict=1, - ) # nosec - - if lead: - last_communication = frappe.get_all( - "Communication", - filters={"reference_doctype": "Lead", "reference_name": lead, "sent_or_received": "Received"}, - fields=["name", "content"], - order_by="`creation` DESC", - limit=1, - ) - - last_communication = last_communication[0] if last_communication else None - - return {"last_communication": last_communication, "last_issue": last_issue} - - def get_last_issue_from_customer(customer_name): issues = frappe.get_all( "Issue", diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 78352735ec1..56222a452d9 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -597,16 +597,16 @@ regional_overrides = { "erpnext.controllers.accounts_controller.validate_regional": "erpnext.regional.italy.utils.sales_invoice_validate", }, } -user_privacy_documents = [ +user_data_fields = [ { "doctype": "Lead", - "match_field": "email_id", - "personal_fields": ["phone", "mobile_no", "fax", "website", "lead_name"], + "filter_by": "email_id", + "redact_fields": ["phone", "mobile_no", "fax", "website", "lead_name"], }, { "doctype": "Opportunity", - "match_field": "contact_email", - "personal_fields": ["contact_mobile", "contact_display", "customer_name"], + "filter_by": "contact_email", + "redact_fields": ["contact_mobile", "contact_display", "customer_name"], }, ] diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index 88a6c3bad66..4608cbcb6cf 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -173,7 +173,9 @@ frappe.ui.form.on("BOM", { frm.set_intro( __("This is a Template BOM and will be used to make the work order for {0} of the item {1}", [ `variants`, - `${frm.doc.item}`, + `${frappe.utils.escape_html( + frm.doc.item + )}`, ]), true ); diff --git a/erpnext/manufacturing/doctype/bom/bom_item_preview.html b/erpnext/manufacturing/doctype/bom/bom_item_preview.html index 2c0f091da58..15d121e5caf 100644 --- a/erpnext/manufacturing/doctype/bom/bom_item_preview.html +++ b/erpnext/manufacturing/doctype/bom/bom_item_preview.html @@ -17,11 +17,11 @@

{% if data.value && data.value != "BOM" %} - + {{ __("Open BOM {0}", [data.value.bold()]) }} {% endif %} {% if data.item_code %} - + {{ __("Open Item {0}", [data.item_code.bold()]) }} {% endif %}

diff --git a/erpnext/manufacturing/doctype/work_order/services/__init__.py b/erpnext/manufacturing/doctype/work_order/services/__init__.py new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/erpnext/manufacturing/doctype/work_order/services/__init__.py @@ -0,0 +1 @@ + diff --git a/erpnext/manufacturing/doctype/work_order/services/material_coverage.py b/erpnext/manufacturing/doctype/work_order/services/material_coverage.py new file mode 100644 index 00000000000..8363e0c1284 --- /dev/null +++ b/erpnext/manufacturing/doctype/work_order/services/material_coverage.py @@ -0,0 +1,22 @@ +# Copyright (c) 2026, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from collections.abc import Mapping + +from frappe.utils import flt + + +def get_minimum_material_coverage_fraction( + required_qty: Mapping[str, float], transferred_qty: Mapping[str, float], precision: int +) -> float: + """Return the least-covered component ratio at the configured quantity precision.""" + coverage = [] + for item_code, required in required_qty.items(): + transferred = flt(transferred_qty.get(item_code)) + # Stored values can differ after the digits that the user can enter or see. + if flt(transferred, precision) == flt(required, precision): + coverage.append(1.0) + else: + coverage.append(transferred / required) + + return min(coverage, default=0.0) diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index 0d421ed4a63..e453dcc26c3 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -1461,9 +1461,11 @@ class TestWorkOrder(FrappeTestCase): del transfer_entry.get("items")[0] # transfer only one RM transfer_entry.submit() - # WO's "Material Transferred for Mfg" shows all is transferred, one RM is pending + # One required item is still missing, so no finished-good quantity is covered yet. work_order.reload() - self.assertEqual(work_order.material_transferred_for_manufacturing, 1) + self.assertEqual(transfer_entry.fg_completed_qty, 0) + self.assertEqual(work_order.material_transferred_for_manufacturing, 0) + self.assertEqual(work_order.status, "In Process") self.assertEqual(work_order.required_items[0].transferred_qty, 0) self.assertEqual(work_order.required_items[1].transferred_qty, 2) @@ -1483,6 +1485,47 @@ class TestWorkOrder(FrappeTestCase): self.assertEqual(work_order.required_items[0].transferred_qty, 1) self.assertEqual(work_order.required_items[1].transferred_qty, 2) + def test_material_transfer_claim_follows_actual_coverage(self): + work_order = make_wo_order_test_record(planned_start_date=now(), qty=4) + test_stock_entry.make_stock_entry( + item_code="_Test Item", target="_Test Warehouse - _TC", qty=10, basic_rate=5000.0 + ) + test_stock_entry.make_stock_entry( + item_code="_Test Item Home Desktop 100", + target="_Test Warehouse - _TC", + qty=20, + basic_rate=1000.0, + ) + + transfer_entry = frappe.get_doc( + make_stock_entry(work_order.name, "Material Transfer for Manufacture", 4) + ) + for row in transfer_entry.items: + if row.item_code == "_Test Item": + row.qty = 1 + transfer_entry.submit() + + work_order.reload() + self.assertEqual(transfer_entry.fg_completed_qty, 1) + self.assertEqual(work_order.material_transferred_for_manufacturing, 1) + + remainder_entry = frappe.get_doc( + make_stock_entry(work_order.name, "Material Transfer for Manufacture", 3) + ) + remainder_entry.submit() + + work_order.reload() + self.assertEqual(remainder_entry.fg_completed_qty, 3) + self.assertEqual(work_order.material_transferred_for_manufacturing, 4) + + def test_material_coverage_cap_skips_manufacture_entry(self): + work_order = make_wo_order_test_record(planned_start_date=now(), qty=1) + manufacture_entry = frappe.get_doc(make_stock_entry(work_order.name, "Manufacture", 1)) + manufacture_entry.pro_doc = work_order + manufacture_entry._action = "submit" + + self.assertFalse(manufacture_entry._should_cap_completed_qty()) + def test_material_transferred_min_fraction_on_partial_pick_list(self): """Pick-list flow (fg_completed_qty = 0): 'Material Transferred for Manufacturing' must reflect the least-transferred required item (the bottleneck), instead of being @@ -1545,6 +1588,97 @@ class TestWorkOrder(FrappeTestCase): work_order.reload() self.assertEqual(work_order.material_transferred_for_manufacturing, 2.0) + def test_material_transferred_ignores_hidden_precision_difference(self): + work_order = make_wo_order_test_record(planned_start_date=now(), qty=2) + test_stock_entry.make_stock_entry( + item_code="_Test Item", target="_Test Warehouse - _TC", qty=10, basic_rate=5000.0 + ) + test_stock_entry.make_stock_entry( + item_code="_Test Item Home Desktop 100", + target="_Test Warehouse - _TC", + qty=10, + basic_rate=1000.0, + ) + + precision = work_order.precision("required_qty", "required_items") + hidden_difference = 4 / (10 ** (precision + 1)) + row = work_order.required_items[0] + row.db_set("required_qty", flt(row.required_qty) + hidden_difference, update_modified=False) + work_order.reload() + required_qty = {row.item_code: flt(row.required_qty) for row in work_order.required_items} + + transfer_entry = frappe.get_doc( + make_stock_entry(work_order.name, "Material Transfer for Manufacture", 0) + ) + for item in transfer_entry.items: + item.qty = flt(required_qty[item.item_code], precision) + item.transfer_qty = item.qty + transfer_entry.submit() + + work_order.reload() + self.assertEqual( + flt(work_order.required_items[0].required_qty, precision), + flt(work_order.required_items[0].transferred_qty, precision), + ) + self.assertEqual(work_order.material_transferred_for_manufacturing, work_order.qty) + + def test_repair_material_transfer_precision_patch(self): + from erpnext.patches.v16_0.repair_work_order_material_transfer import ( + execute, + get_precision_affected_work_orders, + ) + + precision = frappe.get_precision("Work Order Item", "required_qty") + hidden_difference = 4 / (10 ** (precision + 1)) + work_order = make_wo_order_test_record(planned_start_date=now(), qty=2) + for index, row in enumerate(work_order.required_items): + required_qty = flt(row.required_qty) + (hidden_difference if index == 0 else 0) + row.db_set( + { + "required_qty": required_qty, + "transferred_qty": flt(required_qty, precision), + }, + update_modified=False, + ) + work_order.db_set("material_transferred_for_manufacturing", 1.99, update_modified=False) + + partial_work_order = make_wo_order_test_record(planned_start_date=now(), qty=2) + for row in partial_work_order.required_items: + row.db_set("transferred_qty", row.required_qty, update_modified=False) + partial_row = partial_work_order.required_items[0] + partial_row.db_set( + "transferred_qty", + flt(partial_row.required_qty, precision) - (1 / (10**precision)), + update_modified=False, + ) + partial_work_order.db_set("material_transferred_for_manufacturing", 1.99, update_modified=False) + + terminal_work_orders = [] + for status in ("Stopped", "Closed", "Completed"): + terminal_work_order = make_wo_order_test_record(planned_start_date=now(), qty=2) + for row in terminal_work_order.required_items: + row.db_set("transferred_qty", row.required_qty, update_modified=False) + terminal_work_order.db_set( + {"material_transferred_for_manufacturing": 1.99, "status": status}, + update_modified=False, + ) + terminal_work_orders.append(terminal_work_order) + + updates = get_precision_affected_work_orders() + self.assertIn(work_order.name, updates) + self.assertNotIn(partial_work_order.name, updates) + for terminal_work_order in terminal_work_orders: + self.assertNotIn(terminal_work_order.name, updates) + + execute() + work_order.reload() + partial_work_order.reload() + self.assertEqual(work_order.material_transferred_for_manufacturing, work_order.qty) + self.assertEqual(partial_work_order.material_transferred_for_manufacturing, 1.99) + for terminal_work_order in terminal_work_orders: + terminal_work_order.reload() + self.assertEqual(terminal_work_order.material_transferred_for_manufacturing, 1.99) + def test_status_in_process_when_only_one_required_item_transferred(self): """Stock Entry created from a Pick List that picked only one of the required items: min-fraction keeps material_transferred_for_manufacturing at 0, but the work order must diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index d1bfa8edc0d..3397e7940de 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -31,6 +31,10 @@ from erpnext.manufacturing.doctype.bom.bom import ( from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import ( get_mins_between_operations, ) +from erpnext.manufacturing.doctype.work_order.services.material_coverage import ( + get_minimum_material_coverage_fraction, +) +from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults from erpnext.stock.doctype.batch.batch import make_batch from erpnext.stock.doctype.item.item import get_item_defaults, validate_end_of_life from erpnext.stock.doctype.serial_no.serial_no import get_available_serial_nos, get_serial_nos @@ -312,7 +316,18 @@ class WorkOrder(Document): if not self.wip_warehouse and not self.skip_transfer: self.wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse") if not self.fg_warehouse: - self.fg_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_fg_warehouse") + self.fg_warehouse = ( + frappe.db.get_single_value("Manufacturing Settings", "default_fg_warehouse") + or self.get_production_item_warehouse() + ) + + def get_production_item_warehouse(self): + if not self.production_item: + return None + + return get_item_defaults(self.production_item, self.company).get( + "default_warehouse" + ) or get_item_group_defaults(self.production_item, self.company).get("default_warehouse") def check_wip_warehouse_skip(self): if self.skip_transfer and not self.from_wip_warehouse: @@ -412,11 +427,7 @@ class WorkOrder(Document): elif self.docstatus == 1: if status not in ["Closed", "Stopped"]: status = "Not Started" - if ( - flt(self.material_transferred_for_manufacturing) > 0 - or self.skip_transfer - or self.has_transferred_material() - ): + if flt(self.material_transferred_for_manufacturing) > 0 or self.has_transferred_material(): status = "In Process" precision = frappe.get_precision("Work Order", "produced_qty") @@ -436,8 +447,7 @@ class WorkOrder(Document): return status def has_transferred_material(self): - """True if any raw material was transferred against this work order via a pick list - (these leave material_transferred_for_manufacturing at 0 via the min-fraction rule).""" + """True if any raw material was transferred against this work order.""" ste = frappe.qb.DocType("Stock Entry") ste_child = frappe.qb.DocType("Stock Entry Detail") qty = ( @@ -450,7 +460,6 @@ class WorkOrder(Document): & (ste.docstatus == 1) & (ste.purpose == "Material Transfer for Manufacture") & (ste.is_return == 0) - & (ste.pick_list.isnotnull()) ) ).run()[0][0] return flt(qty) > 0 @@ -1231,7 +1240,10 @@ class WorkOrder(Document): "description": item.description, "allow_alternative_item": item.allow_alternative_item, "required_qty": item.qty, - "source_warehouse": item.source_warehouse or item.default_warehouse, + "source_warehouse": item.source_warehouse + or item.default_warehouse + or self.source_warehouse + or get_item_group_defaults(item.item_code, self.company).get("default_warehouse"), "include_item_in_manufacturing": item.include_item_in_manufacturing, }, ) @@ -1274,20 +1286,13 @@ class WorkOrder(Document): self.recompute_material_transferred_for_manufacturing(transferred_items) def recompute_material_transferred_for_manufacturing(self, transferred_items): - """Set material_transferred_for_manufacturing based on actual item-level transfers, not fg_completed_qty.""" + """Set transferred quantity from the raw materials that have actually moved.""" # Job Card transfers use the minimum completed quantity across operations. if self.operations and self.transfer_material_against == "Job Card": return - # When fg_completed_qty > 0 (direct stock entries, excess transfer), preserve the - # SUM(fg_completed_qty) approach so excess-transfer tracking works correctly. - sum_fg_completed_qty = self.get_transferred_or_manufactured_qty("Material Transfer for Manufacture") - if sum_fg_completed_qty: - self.db_set("material_transferred_for_manufacturing", sum_fg_completed_qty) - return + claimed_qty = self.get_transferred_or_manufactured_qty("Material Transfer for Manufacture") - # Pick list flow sets fg_completed_qty=0; use min-fraction of actual item transfers - # so partial availability does not prematurely mark the work order as fully transferred. required_by_item = {} for row in self.required_items: if not row.include_item_in_manufacturing or flt(row.required_qty) <= 0: @@ -1297,12 +1302,13 @@ class WorkOrder(Document): if not required_by_item: return - min_fraction = min( - flt(transferred_items.get(item_code) or 0) / required_qty - for item_code, required_qty in required_by_item.items() + min_fraction = get_minimum_material_coverage_fraction( + required_by_item, + transferred_items, + self.precision("required_qty", "required_items"), ) - min_fraction = min(min_fraction, 1.0) - material_transferred = min_fraction * flt(self.qty) + covered_qty = min_fraction * flt(self.qty) + material_transferred = min(covered_qty, max(flt(self.qty), claimed_qty)) self.db_set("material_transferred_for_manufacturing", material_transferred) def update_returned_qty(self): diff --git a/erpnext/manufacturing/doctype/work_order/work_order_preview.html b/erpnext/manufacturing/doctype/work_order/work_order_preview.html index 95bdd291ee0..112c8d8250e 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order_preview.html +++ b/erpnext/manufacturing/doctype/work_order/work_order_preview.html @@ -20,11 +20,11 @@

{% if data.value %} - + {{ __("Open Work Order {0}", [data.value.bold()]) }} {% endif %} {% if data.item_code %} - + {{ __("Open Item {0}", [data.item_code.bold()]) }} {% endif %}

diff --git a/erpnext/manufacturing/doctype/workstation/workstation.py b/erpnext/manufacturing/doctype/workstation/workstation.py index ac7b5f043e2..dfdd656bccd 100644 --- a/erpnext/manufacturing/doctype/workstation/workstation.py +++ b/erpnext/manufacturing/doctype/workstation/workstation.py @@ -413,7 +413,7 @@ def get_workstations(**kwargs): for d in data: d.workstation_name = get_link_to_form("Workstation", d.name) - d.status_image = d.on_status_image + d.status_image = frappe.utils.escape_html(d.on_status_image) d.background_color = color_map.get(d.status, "var(--red-600)") d.workstation_link = get_url_to_form("Workstation", d.name) if d.status != "Production": diff --git a/erpnext/manufacturing/doctype/workstation/workstation_job_card.html b/erpnext/manufacturing/doctype/workstation/workstation_job_card.html index 97707855db0..db3d3bffcc3 100644 --- a/erpnext/manufacturing/doctype/workstation/workstation_job_card.html +++ b/erpnext/manufacturing/doctype/workstation/workstation_job_card.html @@ -11,7 +11,7 @@
{% $.each(data, (idx, d) => { %} - @@ -77,7 +77,7 @@
{% if(d.make_material_request) { %}
- +
{% } %} diff --git a/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.js b/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.js index 0e89a25c228..8536ccd1993 100644 --- a/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.js +++ b/erpnext/manufacturing/report/production_plan_summary/production_plan_summary.js @@ -23,7 +23,10 @@ frappe.query_reports["Production Plan Summary"] = { if (column.fieldname == "item_code") { var color = data.pending_qty > 0 ? "red" : "green"; - value = `${data["item_code"]}`; + value = `${frappe.utils.escape_html(data["item_code"])}`; } return value; diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 9ca27a734d8..5535458d3ed 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -447,3 +447,5 @@ erpnext.patches.v16_0.rename_ar_ap_ageing_filter erpnext.patches.v15_0.fix_titles erpnext.patches.v16_0.backfill_repost_accounting_ledger_status erpnext.patches.v16_0.merge_seeded_item_group_root +erpnext.patches.v16_0.repair_work_order_material_transfer +erpnext.patches.v16_0.remove_frappe_crm_custom_fields diff --git a/erpnext/patches/v16_0/remove_frappe_crm_custom_fields.py b/erpnext/patches/v16_0/remove_frappe_crm_custom_fields.py new file mode 100644 index 00000000000..3f1c8e1a6f4 --- /dev/null +++ b/erpnext/patches/v16_0/remove_frappe_crm_custom_fields.py @@ -0,0 +1,27 @@ +import frappe +from frappe.custom.doctype.custom_field.custom_field import delete_custom_fields + +from erpnext.crm.doctype.crm_settings.crm_settings import CRMSettings + + +def execute(): + """Delete the `crm_deal` fields on Quotation and Customer if Frappe CRM Data Synchronization is disabled and there's no data on those fields.""" + + crm_deal_exists_in_quotation = frappe.db.has_column("Quotation", "crm_deal") and frappe.get_all( + "Quotation", filters={"crm_deal": ["is", "set"]}, limit=1 + ) + + crm_deal_exists_in_customer = frappe.db.has_column("Customer", "crm_deal") and frappe.get_all( + "Customer", filters={"crm_deal": ["is", "set"]}, limit=1 + ) + + enable_frappe_crm_data_sync = frappe.get_single_value( + "CRM Settings", "enable_frappe_crm_data_synchronization" + ) + + if enable_frappe_crm_data_sync or crm_deal_exists_in_quotation or crm_deal_exists_in_customer: + return + + custom_fields = CRMSettings.get_frappe_crm_custom_fields() + + delete_custom_fields(custom_fields) diff --git a/erpnext/patches/v16_0/repair_work_order_material_transfer.py b/erpnext/patches/v16_0/repair_work_order_material_transfer.py new file mode 100644 index 00000000000..31e119f8442 --- /dev/null +++ b/erpnext/patches/v16_0/repair_work_order_material_transfer.py @@ -0,0 +1,65 @@ +import frappe +from frappe.utils import flt +from pypika import functions as fn + +from erpnext.manufacturing.doctype.work_order.services.material_coverage import ( + get_minimum_material_coverage_fraction, +) + + +def execute(): + updates = get_precision_affected_work_orders() + frappe.db.bulk_update("Work Order", updates, update_modified=False) + + +def get_precision_affected_work_orders(): + """Return Work Orders whose components cover the plan at quantity precision.""" + work_orders = {} + for row in _get_candidate_rows(): + work_order = work_orders.setdefault( + row.work_order, + {"qty": flt(row.qty), "required_qty": {}, "transferred_qty": {}}, + ) + item_code = row.item_code + work_order["required_qty"][item_code] = work_order["required_qty"].get(item_code, 0.0) + flt( + row.required_qty + ) + work_order["transferred_qty"][item_code] = max( + work_order["transferred_qty"].get(item_code, 0.0), flt(row.transferred_qty) + ) + + precision = frappe.get_precision("Work Order Item", "required_qty") + return { + name: {"material_transferred_for_manufacturing": values["qty"]} + for name, values in work_orders.items() + if get_minimum_material_coverage_fraction( + values["required_qty"], values["transferred_qty"], precision + ) + >= 1.0 + } + + +def _get_candidate_rows(): + work_order = frappe.qb.DocType("Work Order") + required_item = frappe.qb.DocType("Work Order Item") + return ( + frappe.qb.from_(work_order) + .inner_join(required_item) + .on(required_item.parent == work_order.name) + .select( + work_order.name.as_("work_order"), + work_order.qty, + required_item.item_code, + required_item.required_qty, + required_item.transferred_qty, + ) + .where( + (work_order.docstatus == 1) + & (work_order.status.notin(["Stopped", "Closed", "Completed"])) + & (fn.Coalesce(work_order.skip_transfer, 0) == 0) + & (fn.Coalesce(work_order.material_transferred_for_manufacturing, 0) < work_order.qty) + & (fn.Coalesce(work_order.transfer_material_against, "") != "Job Card") + & (required_item.include_item_in_manufacturing == 1) + & (required_item.required_qty > 0) + ) + ).run(as_dict=True) diff --git a/erpnext/projects/doctype/project/project_dashboard.html b/erpnext/projects/doctype/project/project_dashboard.html index 1f299e30833..d8467317582 100644 --- a/erpnext/projects/doctype/project/project_dashboard.html +++ b/erpnext/projects/doctype/project/project_dashboard.html @@ -3,7 +3,7 @@ {% for d in data %}
- + {{ d.activity_type || __("Unknown") }}
diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py index 5028c60f1ad..b5e2fbf31df 100755 --- a/erpnext/projects/doctype/task/task.py +++ b/erpnext/projects/doctype/task/task.py @@ -116,19 +116,35 @@ class Task(NestedSet): if not self.project or frappe.flags.in_test: return - if project_end_date := frappe.db.get_value("Project", self.project, "expected_end_date"): - project_end_date = getdate(project_end_date) - for fieldname in ("exp_start_date", "exp_end_date", "act_start_date", "act_end_date"): - task_date = self.get(fieldname) - if task_date and date_diff(project_end_date, getdate(task_date)) < 0: - frappe.throw( - _("{0}'s {1} cannot be after {2}'s Expected End Date.").format( - frappe.bold(frappe.get_desk_link("Task", self.name)), - _(self.meta.get_label(fieldname)), - frappe.bold(frappe.get_desk_link("Project", self.project)), - ), - frappe.exceptions.InvalidDates, - ) + project_start_date, project_end_date = frappe.db.get_value( + "Project", self.project, ["expected_start_date", "expected_end_date"] + ) + + for fieldname in ("exp_start_date", "exp_end_date", "act_start_date", "act_end_date"): + task_date = self.get(fieldname) + if not task_date: + continue + task_date = getdate(task_date) + + if project_end_date and date_diff(getdate(project_end_date), task_date) < 0: + frappe.throw( + _("{0}'s {1} cannot be after {2}'s Expected End Date.").format( + get_link_to_form("Task", self.name), + _(self.meta.get_label(fieldname)), + get_link_to_form("Project", self.project), + ), + frappe.exceptions.InvalidDates, + ) + + if project_start_date and date_diff(task_date, getdate(project_start_date)) < 0: + frappe.throw( + _("{0}'s {1} cannot be before {2}'s Expected Start Date.").format( + get_link_to_form("Task", self.name), + _(self.meta.get_label(fieldname)), + get_link_to_form("Project", self.project), + ), + frappe.exceptions.InvalidDates, + ) def validate_status(self): if self.is_template and self.status != "Template": diff --git a/erpnext/projects/report/timesheet_billing_summary/timesheet_billing_summary.py b/erpnext/projects/report/timesheet_billing_summary/timesheet_billing_summary.py new file mode 100644 index 00000000000..70b3d0c0c80 --- /dev/null +++ b/erpnext/projects/report/timesheet_billing_summary/timesheet_billing_summary.py @@ -0,0 +1,198 @@ +import frappe +from frappe import _ +from frappe.desk.query_report import get_filtered_data +from frappe.model.docstatus import DocStatus +from frappe.utils import add_days, getdate + +VALUE_FIELDNAMES = ("hours", "billing_hours", "billing_amount") + + +def execute(filters=None): + group_fieldname = filters.pop("group_by", None) + + filters = frappe._dict(filters or {}) + columns = get_columns(filters, group_fieldname) + + data = get_data(filters) + data = get_filtered_data("Timesheet", columns, data, frappe.session.user) + report_summary = get_report_summary(data) + + if group_fieldname: + data = group_by(data, group_fieldname) + + return columns, data, None, None, report_summary, 1 + + +def get_columns(filters, group_fieldname=None): + group_columns = { + "date": { + "label": _("Date"), + "fieldtype": "Date", + "fieldname": "date", + "width": 150, + }, + "project": { + "label": _("Project"), + "fieldtype": "Link", + "fieldname": "project", + "options": "Project", + "width": 200, + "hidden": int(bool(filters.get("project"))), + }, + "employee": { + "label": _("Employee ID"), + "fieldtype": "Link", + "fieldname": "employee", + "options": "Employee", + "width": 200, + "hidden": int(bool(filters.get("employee"))), + }, + } + columns = [] + if group_fieldname in group_columns: + # the grouped column labels the group rows: keep it visible even when it is filtered too + group_columns[group_fieldname]["hidden"] = 0 + columns.append(group_columns.pop(group_fieldname)) + + columns.extend(group_columns.values()) + + columns.extend( + [ + { + "label": _("Employee Name"), + "fieldtype": "data", + "fieldname": "employee_name", + "hidden": 1, + }, + { + "label": _("Timesheet"), + "fieldtype": "Link", + "fieldname": "timesheet", + "options": "Timesheet", + "width": 150, + }, + {"label": _("Working Hours"), "fieldtype": "Float", "fieldname": "hours", "width": 150}, + { + "label": _("Billing Hours"), + "fieldtype": "Float", + "fieldname": "billing_hours", + "width": 150, + }, + { + "label": _("Billing Amount"), + "fieldtype": "Currency", + "fieldname": "billing_amount", + "width": 150, + }, + ] + ) + + return columns + + +def get_data(filters): + _filters = [] + if filters.get("employee"): + _filters.append(("employee", "=", filters.get("employee"))) + if filters.get("project"): + _filters.append(("Timesheet Detail", "project", "=", filters.get("project"))) + if filters.get("from_date"): + _filters.append(("Timesheet Detail", "from_time", ">=", filters.get("from_date"))) + if filters.get("to_date"): + _filters.append(("Timesheet Detail", "from_time", "<", add_days(getdate(filters.get("to_date")), 1))) + if not filters.get("include_draft_timesheets"): + _filters.append(("docstatus", "=", DocStatus.submitted())) + else: + _filters.append(("docstatus", "in", (DocStatus.submitted(), DocStatus.draft()))) + + data = frappe.get_list( + "Timesheet", + fields=[ + "name as timesheet", + "`tabTimesheet`.employee", + "`tabTimesheet`.employee_name", + "`tabTimesheet Detail`.from_time as date", + "`tabTimesheet Detail`.project", + "`tabTimesheet Detail`.hours", + "`tabTimesheet Detail`.billing_hours", + "`tabTimesheet Detail`.billing_amount", + ], + filters=_filters, + order_by="`tabTimesheet Detail`.from_time", + ) + + return data + + +def group_by(data, fieldname): + groups = {} + for row in data: + groups.setdefault(get_group_value(row, fieldname), []).append(row) + + grouped_data = [] + for group in sorted(groups, key=lambda g: (g is None, g)): + hours = billing_hours = billing_amount = 0 + child_rows = [] + for row in groups[group]: + hours += row.get("hours") or 0 + billing_hours += row.get("billing_hours") or 0 + billing_amount += row.get("billing_amount") or 0 + + _row = row.copy() + _row[fieldname] = None + _row["indent"] = 1 + _row["is_group"] = 0 + child_rows.append(_row) + + group_row = { + fieldname: group, + "hours": hours, + "billing_hours": billing_hours, + "billing_amount": billing_amount, + "indent": 0, + "is_group": 1, + } + if fieldname == "employee": + group_row["employee_name"] = groups[group][0].get("employee_name") + + grouped_data.append(group_row) + grouped_data.extend(child_rows) + + return grouped_data + + +def get_group_value(row, fieldname): + value = row.get(fieldname) + # `date` is `Timesheet Detail.from_time`, a datetime: everything logged on a day is one group + return getdate(value) if fieldname == "date" and value else value + + +def get_report_summary(data): + if not data: + return None + + totals = dict.fromkeys(VALUE_FIELDNAMES, 0.0) + for row in data: + for value_fieldname in VALUE_FIELDNAMES: + totals[value_fieldname] += row.get(value_fieldname) or 0 + + return [ + { + "value": totals["hours"], + "indicator": "Blue", + "label": _("Total Working Hours"), + "datatype": "Float", + }, + { + "value": totals["billing_hours"], + "indicator": "Blue", + "label": _("Total Billing Hours"), + "datatype": "Float", + }, + { + "value": totals["billing_amount"], + "indicator": "Green", + "label": _("Total Billing Amount"), + "datatype": "Currency", + }, + ] diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index 4d980d7e277..dc1d85b87ab 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -1,6 +1,14 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt +// mirror of erpnext.stock.get_item_details.NOT_APPLICABLE_TAX +erpnext.NOT_APPLICABLE_TAX = "N/A"; + +// Per-charge_type base resolvers, mirror of the `erpnext_taxable_base_resolvers` +// server hook. A localization registers `fn(calc, item, tax)` returning the per-item +// base, so the client preview matches the server for custom charge types. +erpnext.taxable_base_resolvers = erpnext.taxable_base_resolvers || {}; + erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { setup() { this.fetch_round_off_accounts(); @@ -252,28 +260,33 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { $.each(this.frm.doc.items || [], function(n, item) { var item_tax_map = me._load_item_tax_rate(item.item_tax_rate); - var cumulated_tax_fraction = 0.0; - var total_inclusive_tax_amount_per_qty = 0; + var total_tax_slope = 0.0; + var total_tax_intercept = 0; $.each(me.frm.doc["taxes"] || [], function(i, tax) { - var current_tax_fraction = me.get_current_tax_fraction(tax, item_tax_map); - tax.tax_fraction_for_current_item = current_tax_fraction[0]; - var inclusive_tax_amount_per_qty = current_tax_fraction[1]; + var tax_contribution = me.get_current_tax_fraction(tax, item_tax_map, item); + tax.tax_fraction_for_current_item = tax_contribution[0]; + var tax_intercept_per_qty = tax_contribution[1]; + tax.inclusive_amount_per_qty = tax_intercept_per_qty; if(i==0) { tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item; + tax.grand_total_amount_per_qty = tax_intercept_per_qty; } else { + var prev = me.frm.doc["taxes"][i - 1]; tax.grand_total_fraction_for_current_item = - me.frm.doc["taxes"][i-1].grand_total_fraction_for_current_item + + prev.grand_total_fraction_for_current_item + tax.tax_fraction_for_current_item; + tax.grand_total_amount_per_qty = + flt(prev.grand_total_amount_per_qty) + tax_intercept_per_qty; } - cumulated_tax_fraction += tax.tax_fraction_for_current_item; - total_inclusive_tax_amount_per_qty += inclusive_tax_amount_per_qty * flt(item.qty); + total_tax_slope += tax.tax_fraction_for_current_item; + total_tax_intercept += tax_intercept_per_qty * flt(item.qty); }); - if(!me.discount_amount_applied && item.qty && (total_inclusive_tax_amount_per_qty || cumulated_tax_fraction)) { - var amount = flt(item.amount) - total_inclusive_tax_amount_per_qty; - item.net_amount = flt(amount / (1 + cumulated_tax_fraction), precision("net_amount", item)); + if(!me.discount_amount_applied && item.qty && (total_tax_intercept || total_tax_slope)) { + var amount = flt(item.amount) - total_tax_intercept; + item.net_amount = flt(amount / (1 + total_tax_slope), precision("net_amount", item)); item.net_rate = item.qty ? flt(item.net_amount / item.qty, precision("net_rate", item)) : 0; me.set_in_company_currency(item, ["net_rate", "net_amount"]); @@ -281,40 +294,66 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { }); } - get_current_tax_fraction(tax, item_tax_map) { - // Get tax fraction for calculating tax exclusive amount - // from tax inclusive amount - var current_tax_fraction = 0.0; - var inclusive_tax_amount_per_qty = 0; + get_current_tax_fraction(tax, item_tax_map, item) { + // tax = slope * net + intercept. + // Returns [slope, intercept_per_qty] + var tax_slope = 0.0; + var tax_intercept = 0; if(cint(tax.included_in_print_rate)) { var tax_rate = this._get_tax_rate(tax, item_tax_map); + if (tax_rate === erpnext.NOT_APPLICABLE_TAX) { + return [tax_slope, tax_intercept]; + } + if(tax.charge_type == "On Net Total") { - current_tax_fraction = (tax_rate / 100.0); + tax_slope = (tax_rate / 100.0); } else if(tax.charge_type == "On Previous Row Amount") { - current_tax_fraction = (tax_rate / 100.0) * - this.frm.doc["taxes"][cint(tax.row_id) - 1].tax_fraction_for_current_item; + const row = this.frm.doc["taxes"][cint(tax.row_id) - 1]; + tax_slope = (tax_rate / 100.0) * row.tax_fraction_for_current_item; + tax_intercept = (tax_rate / 100.0) * flt(row.inclusive_amount_per_qty); } else if(tax.charge_type == "On Previous Row Total") { - current_tax_fraction = (tax_rate / 100.0) * - this.frm.doc["taxes"][cint(tax.row_id) - 1].grand_total_fraction_for_current_item; + const row = this.frm.doc["taxes"][cint(tax.row_id) - 1]; + tax_slope = (tax_rate / 100.0) * row.grand_total_fraction_for_current_item; + tax_intercept = (tax_rate / 100.0) * flt(row.grand_total_amount_per_qty); } else if (tax.charge_type == "On Item Quantity") { - inclusive_tax_amount_per_qty = flt(tax_rate); + tax_intercept = flt(tax_rate); + } else { + // Custom charge_type: the rate applies to a resolved (fixed) base, + // e.g. a tax on MRP included in the printed price. + const qty = flt(item.qty) || 1; + const base = this.get_item_taxable_base(item, tax); + tax_intercept = ((tax_rate / 100.0) * base) / qty; } } if(tax.add_deduct_tax && tax.add_deduct_tax == "Deduct") { - current_tax_fraction *= -1; - inclusive_tax_amount_per_qty *= -1; + tax_slope *= -1; + tax_intercept *= -1; } - return [current_tax_fraction, inclusive_tax_amount_per_qty]; + return [tax_slope, tax_intercept]; + } + + get_item_taxable_base(item, tax) { + // Mirror of the server get_item_taxable_base: a custom charge_type's resolver + // overrides the base value; otherwise the net amount. + const resolver = erpnext.taxable_base_resolvers[tax.charge_type]; + if (resolver) return flt(resolver(this, item, tax)); + return flt(item.net_amount); } _get_tax_rate(tax, item_tax_map) { - return (Object.keys(item_tax_map).indexOf(tax.account_head) != -1) ? - flt(item_tax_map[tax.account_head], precision("rate", tax)) : tax.rate; + if (tax.account_head in item_tax_map) { + let rate = item_tax_map[tax.account_head]; + if (rate === erpnext.NOT_APPLICABLE_TAX) { + return erpnext.NOT_APPLICABLE_TAX; + } + return flt(rate, precision("rate", tax)); + } + return tax.rate; } calculate_net_total() { @@ -353,6 +392,9 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { } $.each(item_tax_map, function(tax, rate) { + if (rate === erpnext.NOT_APPLICABLE_TAX) { + return; + } let found = (me.frm.doc.taxes || []).find(d => d.account_head === tax); if (!found) { let child = frappe.model.add_child(me.frm.doc, "taxes"); @@ -403,11 +445,14 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { } } + // net_amount is the taxable basis, it feeds no total and is always + // accumulated, unlike tax_amount which is kept from the first pass + tax.net_amount += current_net_amount; + // accumulate tax amount into tax.tax_amount if (tax.charge_type != "Actual" && !(me.discount_amount_applied && me.frm.doc.apply_discount_on=="Grand Total")) { tax.tax_amount += current_tax_amount; - tax.net_amount += current_net_amount; } // store tax_amount for current item as it will be used for @@ -493,6 +538,10 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { var current_tax_amount = 0.0; var current_net_amount = 0.0; + if (tax_rate === erpnext.NOT_APPLICABLE_TAX) { + return [current_net_amount, current_tax_amount]; + } + // To set row_id by default as previous row. if(["On Previous Row Amount", "On Previous Row Total"].includes(tax.charge_type)) { if (tax.idx === 1) { @@ -526,6 +575,11 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { } else if (tax.charge_type == "On Item Quantity") { // don't sum current net amount due to the field being a currency field current_tax_amount = tax_rate * item.qty; + } else { + // Custom charge_type: rate applies to the resolver-provided base. + var resolved_base = this.get_item_taxable_base(item, tax); + current_net_amount = resolved_base; + current_tax_amount = (tax_rate / 100.0) * resolved_base; } if (!tax.dont_recompute_tax) { diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index e7f4cdec979..7a133acaf9e 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -818,6 +818,9 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe } $.each(item_tax_map, function(tax, rate) { + if (rate === erpnext.NOT_APPLICABLE_TAX) { + return; + } let found = (me.frm.doc.taxes || []).find(d => d.account_head === tax); if(!found) { let child = frappe.model.add_child(me.frm.doc, "taxes"); @@ -1611,9 +1614,9 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe } if (this.frm.doc.taxes && this.frm.doc.taxes.length > 0) { - this.frm.set_currency_labels(["tax_amount", "total", "tax_amount_after_discount"], this.frm.doc.currency, "taxes"); + this.frm.set_currency_labels(["net_amount", "tax_amount", "total", "tax_amount_after_discount"], this.frm.doc.currency, "taxes"); - this.frm.set_currency_labels(["base_tax_amount", "base_total", "base_tax_amount_after_discount"], company_currency, "taxes"); + this.frm.set_currency_labels(["base_net_amount", "base_tax_amount", "base_total", "base_tax_amount_after_discount"], company_currency, "taxes"); } if (this.frm.doc.advances && this.frm.doc.advances.length > 0) { diff --git a/erpnext/public/js/queries.js b/erpnext/public/js/queries.js index 8b174da244f..32a4e0958c9 100644 --- a/erpnext/public/js/queries.js +++ b/erpnext/public/js/queries.js @@ -12,6 +12,10 @@ $.extend(erpnext.queries, { return { query: "erpnext.controllers.queries.lead_query" }; }, + customer: function () { + return { filters: { disabled: 0 } }; + }, + item: function (filters) { var args = { query: "erpnext.controllers.queries.item_query" }; if (filters) args["filters"] = filters; diff --git a/erpnext/public/js/templates/call_link.html b/erpnext/public/js/templates/call_link.html index 071078c776e..bb49c6b402b 100644 --- a/erpnext/public/js/templates/call_link.html +++ b/erpnext/public/js/templates/call_link.html @@ -8,7 +8,7 @@ • {{ comment_when(creation) }}
- + @@ -34,7 +34,7 @@
{% } %} diff --git a/erpnext/public/js/templates/crm_activities.html b/erpnext/public/js/templates/crm_activities.html index 42603196087..c6561dabf03 100644 --- a/erpnext/public/js/templates/crm_activities.html +++ b/erpnext/public/js/templates/crm_activities.html @@ -30,13 +30,13 @@
- + {%= tasks[i].description %}
+ name="{{ frappe.utils.escape_html(tasks[i].name) }}" title="{{ __('Mark As Closed') }}">
{% if(tasks[i].date) { %} @@ -73,13 +73,13 @@ - - {%= events[i].subject %} + + {%= frappe.utils.escape_html(events[i].subject) %}
+ name="{{ frappe.utils.escape_html(events[i].name) }}" title="{{ __('Mark As Closed') }}">
diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js index 91cda58718c..14011751d3f 100644 --- a/erpnext/public/js/utils/serial_no_batch_selector.js +++ b/erpnext/public/js/utils/serial_no_batch_selector.js @@ -8,6 +8,16 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate { ? this.item.rejected_serial_and_batch_bundle : this.item.serial_and_batch_bundle; + this.init(); + } + + async init() { + try { + this.based_on = await erpnext.stock.get_pick_serial_batch_based_on(); + } catch (e) { + this.based_on = "FIFO"; + } + this.make(); this.render_data(); } @@ -379,7 +389,7 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate { { fieldtype: "Select", options: ["FIFO", "LIFO", "Expiry"], - default: "FIFO", + default: this.based_on, fieldname: "based_on", label: __("Fetch Based On"), onchange: () => this.get_auto_data(), @@ -525,7 +535,7 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate { } if (!based_on) { - based_on = "FIFO"; + based_on = this.based_on; } let warehouse = this.item.warehouse || this.item.s_warehouse; @@ -658,6 +668,27 @@ erpnext.SerialBatchPackageSelector = class SerialNoBatchBundleUpdate { frappe.throw(__("Rejected Warehouse and Accepted Warehouse cannot be same.")); } + let qty_to_fetch = flt(this.dialog.get_value("qty")); + let total_qty = entries.reduce((total, row) => total + (flt(row.qty) || 1.0), 0); + + if (flt(total_qty, 6) !== flt(qty_to_fetch, 6)) { + const confirm_dialog = frappe.confirm( + __( + "Total qty of the rows ({0}) does not match the Qty to Fetch ({1}). Qty of the item will be changed to {0}. Are you sure want to proceed?", + [format_number(total_qty), format_number(qty_to_fetch)] + ), + () => this.create_bundle_entries(entries, warehouse) + ); + confirm_dialog.indicator = "blue"; + confirm_dialog.set_indicator(); + + return; + } + + this.create_bundle_entries(entries, warehouse); + } + + create_bundle_entries(entries, warehouse) { frappe .call({ method: "erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle.add_serial_batch_ledgers", diff --git a/erpnext/regional/italy/e-invoice.xml b/erpnext/regional/italy/e-invoice.xml index ef1e94ff27b..43ea59a26d9 100644 --- a/erpnext/regional/italy/e-invoice.xml +++ b/erpnext/regional/italy/e-invoice.xml @@ -191,7 +191,7 @@ {{ html2text(item.description or '') or item.item_name }} {{ format_float(item.qty) }} {{ item.stock_uom }} - {%- set item_unit_net_price = (item.price_list_rate / tax_divisor) or (item.net_rate) or (item.rate / tax_divisor) %} + {%- set item_unit_net_price = ((item.price_list_rate or 0) / tax_divisor) or (item.net_rate) or (item.rate / tax_divisor) %} {{ format_float(item_unit_net_price, item_meta.get_field("rate").precision) }} {{ render_discount_or_margin(item, tax_divisor) }} {{ format_float(item.net_amount, item_meta.get_field("amount").precision) }} diff --git a/erpnext/regional/italy/test_italy.py b/erpnext/regional/italy/test_italy.py new file mode 100644 index 00000000000..57b6704e867 --- /dev/null +++ b/erpnext/regional/italy/test_italy.py @@ -0,0 +1,80 @@ +import frappe +from frappe.tests.utils import FrappeTestCase + +from erpnext.regional.italy.utils import get_invoice_summary + +VAT_7 = "_Test Italy VAT 7 - _TC" +VAT_19 = "_Test Italy VAT 19 - _TC" + + +def make_item(item_code, net_amount, tax_amount, item_tax_rate): + return frappe._dict( + item_code=item_code, + net_amount=net_amount, + tax_amount=tax_amount, + item_tax_rate=item_tax_rate, + ) + + +def make_tax(account_head, total, charge_type="On Net Total", **kwargs): + return frappe._dict( + charge_type=charge_type, + account_head=account_head, + rate=0, + total=total, + tax_exemption_reason="N4-esenti", + tax_exemption_law="Art.10", + **kwargs, + ) + + +class TestItalyInvoiceSummary(FrappeTestCase): + def test_not_applicable_tax_excluded_from_summary(self): + """An item that marks a tax not applicable belongs to another summary + block. Counting it here inflates DatiRiepilogo and emits a block with + AliquotaIVA 0.00 and no Natura, which SDI rejects.""" + items = [ + make_item("A", 100.0, 7.0, {VAT_7: 7.0, VAT_19: "N/A"}), + make_item("B", 100.0, 19.0, {VAT_7: "N/A", VAT_19: 19.0}), + ] + taxes = [make_tax(VAT_7, 107.0), make_tax(VAT_19, 126.0)] + + summary = get_invoice_summary(items, taxes) + + self.assertEqual(sorted(summary.keys()), ["19.0", "7.0"]) + self.assertEqual(summary["7.0"]["taxable_amount"], 100.0) + self.assertEqual(summary["19.0"]["taxable_amount"], 100.0) + + def test_zero_rated_tax_keeps_exemption_reason(self): + """A genuine 0% rate is still exempt and must carry its Natura.""" + items = [make_item("C", 100.0, 0.0, {VAT_7: 0.0})] + + summary = get_invoice_summary(items, [make_tax(VAT_7, 100.0)]) + + self.assertEqual(list(summary.keys()), ["0.0"]) + self.assertEqual(summary["0.0"]["taxable_amount"], 100.0) + self.assertEqual(summary["0.0"]["tax_exemption_reason"], "N4-esenti") + + def test_all_items_not_applicable_falls_back_to_zero_vat(self): + """With every item excluded the summary would be empty, so the existing + zero VAT fallback has to supply the block and its Natura.""" + items = [make_item("D", 100.0, 0.0, {VAT_7: "N/A"})] + + summary = get_invoice_summary(items, [make_tax(VAT_7, 100.0)]) + + self.assertEqual(list(summary.keys()), ["0.0"]) + self.assertEqual(summary["0.0"]["tax_exemption_reason"], "N4-esenti") + + def test_previous_row_tax_with_only_not_applicable_items(self): + """The summary key leaks out of the item loop and is read again for + previous-row charges. Every item being excluded leaves it unset.""" + items = [make_item("A", 100.0, 0.0, {VAT_7: 0.0, VAT_19: "N/A"})] + taxes = [ + make_tax(VAT_7, 100.0, idx=1), + make_tax(VAT_19, 100.0, charge_type="On Previous Row Total", idx=2, row_id=None), + ] + + summary = get_invoice_summary(items, taxes) + + self.assertEqual(list(summary.keys()), ["0.0"]) + self.assertEqual(summary["0.0"]["taxable_amount"], 100.0) diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py index 8e216644857..ef35ad26ab6 100644 --- a/erpnext/regional/italy/utils.py +++ b/erpnext/regional/italy/utils.py @@ -8,6 +8,7 @@ from frappe.utils.file_manager import remove_file from erpnext.controllers.taxes_and_totals import get_itemised_tax from erpnext.regional.italy import state_codes +from erpnext.stock.get_item_details import NOT_APPLICABLE_TAX def update_itemised_tax_data(doc): @@ -171,13 +172,20 @@ def get_invoice_summary(items, taxes): # Check item tax rates if tax rate is zero. if tax.rate == 0: + key = None for item in items: item_tax_rate = item.item_tax_rate if isinstance(item.item_tax_rate, str): item_tax_rate = json.loads(item.item_tax_rate) if item_tax_rate and tax.account_head in item_tax_rate: - key = cstr(item_tax_rate[tax.account_head]) + rate = item_tax_rate[tax.account_head] + if rate == NOT_APPLICABLE_TAX: + # the tax does not apply to this item, so the item belongs + # to another summary block and must not be counted here + continue + + key = cstr(rate) if key not in summary_data: summary_data.setdefault( key, @@ -195,10 +203,15 @@ def get_invoice_summary(items, taxes): summary_data[key]["tax_exemption_reason"] = tax.tax_exemption_reason summary_data[key]["tax_exemption_law"] = tax.tax_exemption_law - if summary_data.get("0.0") and tax.charge_type in [ - "On Previous Row Total", - "On Previous Row Amount", - ]: + if ( + key + and summary_data.get("0.0") + and tax.charge_type + in [ + "On Previous Row Total", + "On Previous Row Amount", + ] + ): summary_data[key]["taxable_amount"] = tax.total if summary_data == {}: # Implies that Zero VAT has not been set on any item. diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py index e6ed7acb508..cc6c55a37f1 100644 --- a/erpnext/selling/doctype/customer/test_customer.py +++ b/erpnext/selling/doctype/customer/test_customer.py @@ -67,7 +67,7 @@ class TestCustomer(FrappeTestCase): doc.delete() def test_party_details(self): - from erpnext.accounts.party import get_party_details + from erpnext.accounts.party import _get_party_details to_check = { "selling_price_list": None, @@ -91,7 +91,7 @@ class TestCustomer(FrappeTestCase): "Contact", "_Test Contact for _Test Customer-_Test Customer", "is_primary_contact", 1 ) - details = get_party_details("_Test Customer") + details = _get_party_details("_Test Customer") for key, value in to_check.items(): val = details.get(key) @@ -101,13 +101,13 @@ class TestCustomer(FrappeTestCase): self.assertEqual(value, val) def test_party_details_tax_category(self): - from erpnext.accounts.party import get_party_details + from erpnext.accounts.party import _get_party_details frappe.delete_doc_if_exists("Address", "_Test Address With Tax Category-Billing") frappe.delete_doc_if_exists("Address", "_Test Address With Tax Category-Shipping") # Tax Category without Address - details = get_party_details("_Test Customer With Tax Category") + details = _get_party_details("_Test Customer With Tax Category") self.assertEqual(details.tax_category, "_Test Tax Category 1") billing_address = frappe.get_doc( @@ -141,13 +141,13 @@ class TestCustomer(FrappeTestCase): # Tax Category from Billing Address settings.determine_address_tax_category_from = "Billing Address" settings.save() - details = get_party_details("_Test Customer With Tax Category") + details = _get_party_details("_Test Customer With Tax Category") self.assertEqual(details.tax_category, "_Test Tax Category 2") # Tax Category from Shipping Address settings.determine_address_tax_category_from = "Shipping Address" settings.save() - details = get_party_details("_Test Customer With Tax Category") + details = _get_party_details("_Test Customer With Tax Category") self.assertEqual(details.tax_category, "_Test Tax Category 3") # Rollback diff --git a/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py b/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py index 84da765d930..46056c94129 100644 --- a/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py +++ b/erpnext/selling/report/customer_wise_item_price/customer_wise_item_price.py @@ -7,7 +7,7 @@ from frappe import _, qb from frappe.query_builder import Criterion from erpnext import get_default_company -from erpnext.accounts.party import get_party_details +from erpnext.accounts.party import _get_party_details def execute(filters=None): @@ -125,7 +125,7 @@ def get_data(filters=None): def get_customer_details(filters): - customer_details = get_party_details(party=filters.get("customer"), party_type="Customer") + customer_details = _get_party_details(party=filters.get("customer"), party_type="Customer") customer_details.update( {"company": get_default_company(), "price_list": customer_details.get("selling_price_list")} ) diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py index ea25bd033b9..eb01d7234d4 100644 --- a/erpnext/setup/doctype/email_digest/email_digest.py +++ b/erpnext/setup/doctype/email_digest/email_digest.py @@ -901,7 +901,9 @@ def send(): @frappe.whitelist() def get_digest_msg(name): - return frappe.get_doc("Email Digest", name).get_msg_html() + email_digest = frappe.get_doc("Email Digest", name) + email_digest.check_permission() + return email_digest.get_msg_html() def get_incomes_expenses_for_period(account, from_date, to_date): diff --git a/erpnext/startup/boot.py b/erpnext/startup/boot.py index ff1141fb07e..ffe81ab3915 100644 --- a/erpnext/startup/boot.py +++ b/erpnext/startup/boot.py @@ -25,6 +25,9 @@ def boot_session(bootinfo): bootinfo.sysdefaults.over_billing_allowance = frappe.db.get_single_value( "Accounts Settings", "over_billing_allowance" ) + bootinfo.sysdefaults.disable_include_dimensions = cint( + frappe.get_single_value("Accounts Settings", "disable_include_dimensions") + ) bootinfo.sysdefaults.quotation_valid_till = cint( frappe.db.get_single_value("CRM Settings", "default_valid_till") diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index 47dd2f50656..cfdb4d04250 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -188,7 +188,10 @@ frappe.ui.form.on("Item", { if (frm.doc.variant_of) { frm.set_intro( __("This Item is a Variant of {0} (Template).", [ - `${frm.doc.variant_of}`, + `${frappe.utils.escape_html(frm.doc.variant_of)}`, ]), true ); diff --git a/erpnext/stock/doctype/item_price/item_price.json b/erpnext/stock/doctype/item_price/item_price.json index c6950b9a10f..95d5dbe9147 100644 --- a/erpnext/stock/doctype/item_price/item_price.json +++ b/erpnext/stock/doctype/item_price/item_price.json @@ -89,7 +89,7 @@ }, { "fieldname": "item_description", - "fieldtype": "Text", + "fieldtype": "Text Editor", "label": "Item Description", "read_only": 1 }, @@ -224,7 +224,7 @@ "idx": 1, "index_web_pages_for_search": 1, "links": [], - "modified": "2024-04-02 22:18:00.450641", + "modified": "2026-08-12 13:14:41.847412", "modified_by": "Administrator", "module": "Stock", "name": "Item Price", @@ -264,4 +264,4 @@ "states": [], "title_field": "item_name", "track_changes": 1 -} \ No newline at end of file +} diff --git a/erpnext/stock/doctype/item_price/item_price.py b/erpnext/stock/doctype/item_price/item_price.py index dc693890cd7..c982a2f706f 100644 --- a/erpnext/stock/doctype/item_price/item_price.py +++ b/erpnext/stock/doctype/item_price/item_price.py @@ -28,7 +28,7 @@ class ItemPrice(Document): currency: DF.Link | None customer: DF.Link | None item_code: DF.Link - item_description: DF.Text | None + item_description: DF.TextEditor | None item_name: DF.Data | None lead_time_days: DF.Int note: DF.Text | None diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 25c6fd987f5..f7df8ecd9f3 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -372,6 +372,9 @@ class PurchaseReceipt(BuyingController): # Check for Closed status def check_on_hold_or_closed_status(self): + if self.get("is_return"): + return + check_list = [] for d in self.get("items"): if d.meta.get_field("purchase_order") and d.purchase_order and d.purchase_order not in check_list: diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 40cf324010d..f30158b4f51 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -708,6 +708,43 @@ class TestPurchaseReceipt(FrappeTestCase): update_purchase_receipt_status(pr.name, "Closed") self.assertEqual(frappe.db.get_value("Purchase Receipt", pr.name, "status"), "Closed") + def test_purchase_return_against_closed_purchase_order(self): + from erpnext.buying.doctype.purchase_order.purchase_order import ( + make_purchase_receipt as make_pr_from_po, + ) + from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order + from erpnext.controllers.sales_and_purchase_return import make_return_doc + + po = create_purchase_order(qty=2, rate=100) + + receipts = [] + for _ in range(2): + pr = make_pr_from_po(po.name) + pr.items[0].qty = pr.items[0].received_qty = 1 + pr.submit() + receipts.append(pr) + + first_return = make_return_doc("Purchase Receipt", receipts[0].name) + first_return.submit() + + po.reload() + po.update_status("Closed") + + # a return against a closed Purchase Order should still go through, + # the same way a Delivery Note return does against a closed Sales Order + second_return = make_return_doc("Purchase Receipt", receipts[1].name) + second_return.submit() + + self.assertEqual(second_return.docstatus, 1) + self.assertEqual(frappe.db.get_value("Purchase Order", po.name, "status"), "Closed") + + # cancelling the return runs the same check on the closed order + second_return.cancel() + + # a regular receipt against the closed order must still be blocked + blocked_pr = make_pr_from_po(po.name) + self.assertRaisesRegex(frappe.InvalidStatusError, "Closed", blocked_pr.save) + def test_pr_billing_status(self): """Flow: 1. PO -> PR1 -> PI diff --git a/erpnext/stock/doctype/shipment/shipment.js b/erpnext/stock/doctype/shipment/shipment.js index f22139c89f5..9c86fefc183 100644 --- a/erpnext/stock/doctype/shipment/shipment.js +++ b/erpnext/stock/doctype/shipment/shipment.js @@ -174,7 +174,10 @@ frappe.ui.form.on("Shipment", { __("Email or Phone/Mobile of the Contact are mandatory to continue.") + "
" + __("Please set Email/Phone for the contact") + - ` ${contact_name}` + ` ${frappe.utils.escape_html(contact_name)}` ); } let contact_display = r.message.contact_display; diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index c50671d9d3f..0541193184c 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -32,6 +32,9 @@ from erpnext.manufacturing.doctype.bom.bom import ( get_scrap_items_from_sub_assemblies, validate_bom_no, ) +from erpnext.manufacturing.doctype.work_order.services.material_coverage import ( + get_minimum_material_coverage_fraction, +) from erpnext.setup.doctype.brand.brand import get_brand_defaults from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults from erpnext.stock.doctype.batch.batch import get_batch_qty @@ -262,6 +265,7 @@ class StockEntry(StockController): self.calculate_rate_and_amount() self.validate_putaway_capacity() self.validate_component_and_quantities() + self._cap_completed_qty_to_material_coverage() self.validate_finished_good_serial_batch_for_work_order() if not self.get("purpose") == "Manufacture": @@ -1186,6 +1190,67 @@ class StockEntry(StockController): title=_("Missing Item"), ) + def _cap_completed_qty_to_material_coverage(self): + if not self._should_cap_completed_qty(): + return + # Keep an excessive claim intact so the Work Order allowance check can reject it. + max_qty = flt(self.pro_doc.qty) + overproduction_percentage = flt( + frappe.db.get_single_value("Manufacturing Settings", "overproduction_percentage_for_work_order") + ) + to_transfer_qty = flt(self.pro_doc.material_transferred_for_manufacturing) + flt( + self.fg_completed_qty + ) + transfer_limit_qty = max_qty + (max_qty * overproduction_percentage / 100) + if transfer_limit_qty < to_transfer_qty: + return + + required_qty, transferred_qty = self._get_work_order_material_qty() + if not required_qty: + return + + covered_before = self._get_covered_work_order_qty(required_qty, transferred_qty) + for row in self.items: + item_code = row.original_item or row.item_code + if row.s_warehouse and item_code in required_qty: + transferred_qty[item_code] += flt(row.qty) * flt(row.conversion_factor or 1) + + covered_after = self._get_covered_work_order_qty(required_qty, transferred_qty) + covered_by_entry = flt(max(covered_after - covered_before, 0), self.precision("fg_completed_qty")) + self.fg_completed_qty = min(flt(self.fg_completed_qty), covered_by_entry) + + def _should_cap_completed_qty(self): + if self.get("_action") != "submit": + return False + if self.purpose != "Material Transfer for Manufacture": + return False + if not self.pro_doc or not self.fg_completed_qty: + return False + if self.is_return or self.get("is_additional_transfer_entry"): + return False + return not (self.pro_doc.operations and self.pro_doc.transfer_material_against == "Job Card") + + def _get_work_order_material_qty(self): + required_qty = {} + transferred_qty = {} + for row in self.pro_doc.required_items: + if not row.include_item_in_manufacturing or flt(row.required_qty) <= 0: + continue + required_qty[row.item_code] = required_qty.get(row.item_code, 0.0) + flt(row.required_qty) + # Duplicate required-item rows each hold the aggregate transferred quantity. + transferred_qty[row.item_code] = max( + transferred_qty.get(row.item_code, 0.0), flt(row.transferred_qty) + ) + return required_qty, transferred_qty + + def _get_covered_work_order_qty(self, required_qty, transferred_qty): + min_fraction = get_minimum_material_coverage_fraction( + required_qty, + transferred_qty, + self.pro_doc.precision("required_qty", "required_items"), + ) + return min_fraction * flt(self.pro_doc.qty) + def _validate_no_excess_transfer(self): if self.is_return: return diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 9f84909b432..9470795f13f 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -1162,12 +1162,15 @@ def get_item_and_warehouses(item_code, warehouse): from frappe.utils.nestedset import get_descendants_of items = [] + stock_uom = frappe.get_cached_value("Item", item_code, "stock_uom") if frappe.get_cached_value("Warehouse", warehouse, "is_group"): childrens = get_descendants_of("Warehouse", warehouse, ignore_permissions=True, order_by="lft") for ch_warehouse in childrens: - items.append(frappe._dict({"item_code": item_code, "warehouse": ch_warehouse})) + items.append( + frappe._dict({"item_code": item_code, "warehouse": ch_warehouse, "stock_uom": stock_uom}) + ) else: - items = [frappe._dict({"item_code": item_code, "warehouse": warehouse})] + items = [frappe._dict({"item_code": item_code, "warehouse": warehouse, "stock_uom": stock_uom})] return items @@ -1177,7 +1180,8 @@ def get_items_for_stock_reco(warehouse, company): items = frappe.db.sql( f""" select - i.name as item_code, i.item_name, bin.warehouse as warehouse, i.has_serial_no, i.has_batch_no + i.name as item_code, i.item_name, bin.warehouse as warehouse, i.has_serial_no, i.has_batch_no, + i.stock_uom from `tabBin` bin, `tabItem` i where @@ -1195,7 +1199,8 @@ def get_items_for_stock_reco(warehouse, company): items += frappe.db.sql( """ select - i.name as item_code, i.item_name, id.default_warehouse as warehouse, i.has_serial_no, i.has_batch_no + i.name as item_code, i.item_name, id.default_warehouse as warehouse, i.has_serial_no, + i.has_batch_no, i.stock_uom from `tabItem` i, `tabItem Default` id where @@ -1241,6 +1246,7 @@ def get_item_data(row, qty, valuation_rate, serial_no=None): "current_serial_no": serial_no, "serial_no": serial_no, "batch_no": row.get("batch_no"), + "stock_uom": row.get("stock_uom"), } @@ -1268,6 +1274,7 @@ def get_itemwise_batch(warehouse, posting_date, company, item_code=None): "valuation_rate": row[9], "item_name": row[1], "batch_no": row[4], + "stock_uom": row[11], } ) ) diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py index 11d7850913e..835f2a25f9f 100644 --- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py @@ -141,6 +141,7 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin): "_Test Stock Reco Item", is_stock_item=1, valuation_rate=100, + stock_uom="_Test UOM", warehouse="_Test Warehouse Ledger 1 - _TC", opening_stock=100, ) @@ -148,8 +149,8 @@ class TestStockReconciliation(FrappeTestCase, StockTestMixin): items = get_items("_Test Warehouse Group 1 - _TC", nowdate(), nowtime(), "_Test Company") self.assertEqual( - ["_Test Stock Reco Item", "_Test Warehouse Ledger 1 - _TC", 100], - [items[0]["item_code"], items[0]["warehouse"], items[0]["qty"]], + ["_Test Stock Reco Item", "_Test Warehouse Ledger 1 - _TC", 100, "_Test UOM"], + [items[0]["item_code"], items[0]["warehouse"], items[0]["qty"], items[0]["stock_uom"]], ) def test_stock_reco_for_serialized_item(self): diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index aecc20d8aa2..c9fa5fe6e16 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -34,6 +34,8 @@ purchase_doctypes = [ "Purchase Invoice", ] +NOT_APPLICABLE_TAX = "N/A" + @frappe.whitelist() def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=True): @@ -806,7 +808,10 @@ def get_item_tax_map(company, item_tax_template, as_json=True): template = frappe.get_cached_doc("Item Tax Template", item_tax_template) for d in template.taxes: if frappe.get_cached_value("Account", d.tax_type, "company") == company: - item_tax_map[d.tax_type] = d.tax_rate + if d.get("not_applicable"): + item_tax_map[d.tax_type] = NOT_APPLICABLE_TAX + else: + item_tax_map[d.tax_type] = d.tax_rate return json.dumps(item_tax_map) if as_json else item_tax_map diff --git a/erpnext/stock/report/available_batch_report/available_batch_report.py b/erpnext/stock/report/available_batch_report/available_batch_report.py index e5f14315773..84a671431ed 100644 --- a/erpnext/stock/report/available_batch_report/available_batch_report.py +++ b/erpnext/stock/report/available_batch_report/available_batch_report.py @@ -154,6 +154,9 @@ def get_batchwise_data_from_serial_batch_bundle(batchwise_data, filters): def get_query_based_on_filters(query, batch, table, filters): + if filters.company: + query = query.where(table.company == filters.company) + if filters.item_code: query = query.where(table.item_code == filters.item_code) diff --git a/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.js b/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.js index c38f0237436..6df8458fd3c 100644 --- a/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.js +++ b/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.js @@ -2,6 +2,30 @@ // For license information, please see license.txt frappe.query_reports["Stock Qty vs Serial No Count"] = { + onload: function (report) { + report.page.add_inner_button(__("Sync Serial No Status"), () => { + const warehouse = report.get_filter_value("warehouse"); + if (!warehouse) { + frappe.msgprint(__("Please select a warehouse first.")); + return; + } + + frappe.confirm( + __( + "This will update the warehouse and status of Serial Nos counted in {0} to match the stock ledger. Continue?", + [warehouse.bold()] + ), + () => { + frappe.call({ + method: "erpnext.stock.report.stock_qty_vs_serial_no_count.stock_qty_vs_serial_no_count.sync_serial_no_status", + args: { warehouse: warehouse }, + freeze: true, + }); + } + ); + }); + }, + filters: [ { fieldname: "company", diff --git a/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py b/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py index 6087c747374..bc83c8a35e5 100644 --- a/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py +++ b/erpnext/stock/report/stock_qty_vs_serial_no_count/stock_qty_vs_serial_no_count.py @@ -4,6 +4,12 @@ import frappe from frappe import _ +from frappe.query_builder import Order +from frappe.query_builder.functions import Coalesce, Sum +from frappe.utils import cstr, flt +from pypika import analytics as an + +from erpnext.stock.serial_batch_bundle import get_serial_no_status def execute(filters=None): @@ -38,7 +44,20 @@ def get_columns(): return columns +def get_warehouses(warehouse): + if frappe.db.get_value("Warehouse", warehouse, "is_group"): + from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses + + return get_child_warehouses(warehouse) + + return [warehouse] + + def get_data(warehouse, show_disabled_items): + # A group (parent) warehouse holds no stock itself; stock lives in its child + # warehouses. Expand it to all its descendants so the report aggregates them. + warehouses = get_warehouses(warehouse) + filters = {"has_serial_no": True} if not show_disabled_items: filters["disabled"] = False @@ -53,16 +72,23 @@ def get_data(warehouse, show_disabled_items): for item in serial_item_list: total_serial_no = frappe.db.count( "Serial No", - filters={"item_code": item.item_code, "status": ("in", status_list), "warehouse": warehouse}, + filters={ + "item_code": item.item_code, + "status": ("in", status_list), + "warehouse": ("in", warehouses), + }, ) - actual_qty = frappe.db.get_value( - "Bin", fieldname=["actual_qty"], filters={"warehouse": warehouse, "item_code": item.item_code} - ) + bin_table = frappe.qb.DocType("Bin") + bin_qty = ( + frappe.qb.from_(bin_table) + .select(Sum(bin_table.actual_qty)) + .where(bin_table.item_code == item.item_code) + .where(bin_table.warehouse.isin(warehouses)) + ).run() - # frappe.db.get_value returns null if no record exist. - if not actual_qty: - actual_qty = 0 + # Sum is null when no Bin record exists for the item in these warehouses. + actual_qty = flt(bin_qty[0][0]) if bin_qty else 0 difference = total_serial_no - actual_qty @@ -77,3 +103,172 @@ def get_data(warehouse, show_disabled_items): data.append(row) return data + + +SYNC_CHUNK_SIZE = 1000 + + +@frappe.whitelist(methods=["POST"]) +def sync_serial_no_status(warehouse: str, item_code: str | None = None): + if not frappe.has_permission("Serial No", "write"): + frappe.throw(_("Not permitted to update Serial No"), frappe.PermissionError) + + warehouse = cstr(warehouse) + item_code = cstr(item_code) if item_code else None + if not frappe.db.exists("Warehouse", warehouse): + frappe.throw(_("Warehouse {0} does not exist").format(warehouse)) + + if item_code and not frappe.db.exists("Item", item_code): + frappe.throw(_("Item {0} does not exist").format(item_code)) + + frappe.enqueue( + sync_serial_no_status_for_warehouse, + queue="long", + warehouse=warehouse, + item_code=item_code, + ) + frappe.msgprint( + _("Serial No status sync has been queued. Reload the report after a few minutes."), + alert=True, + ) + + +def sync_serial_no_status_for_warehouse(warehouse, item_code=None): + filters = {"has_serial_no": 1} + if item_code: + filters["name"] = item_code + + for item in frappe.get_all("Item", filters=filters, pluck="name"): + sync_serial_no_status_for_item(item, warehouse) + + +def sync_serial_no_status_for_item(item_code, warehouse): + """Correct Serial No records this report counts in the warehouse but whose last + stock ledger movement says the stock left it. Reposting rebuilds qty and valuation + from the ledger but never rewrites Serial No warehouse/status, so records orphaned + by cancelled or amended vouchers keep inflating the serial count.""" + serial_nos = frappe.get_all( + "Serial No", + filters={"item_code": item_code, "warehouse": warehouse, "status": ("in", ["Active", "Expired"])}, + pluck="name", + ) + if not serial_nos: + return + + last_moves = get_last_ledger_moves(item_code, serial_nos) + for serial_no in serial_nos: + row = last_moves.get(serial_no) + if row and flt(row.qty) > 0 and row.warehouse == warehouse: + continue + + set_serial_no_state_from_ledger(serial_no, row) + + +def set_serial_no_state_from_ledger(serial_no, row): + if not row: + frappe.db.set_value( + "Serial No", serial_no, {"warehouse": None, "status": "Inactive"}, update_modified=False + ) + return + + status = get_serial_no_status( + frappe._dict( + actual_qty=flt(row.qty), + warehouse=row.warehouse, + voucher_type=row.voucher_type, + voucher_no=row.voucher_no, + is_cancelled=0, + ) + ) + warehouse = row.warehouse if status == "Active" else None + frappe.db.set_value( + "Serial No", serial_no, {"warehouse": warehouse, "status": status}, update_modified=False + ) + + +def get_last_ledger_moves(item_code, serial_nos): + last_moves = get_last_bundle_moves(item_code, serial_nos) + if missing := [serial_no for serial_no in serial_nos if serial_no not in last_moves]: + set_legacy_last_moves(item_code, missing, last_moves) + + return last_moves + + +def get_last_bundle_moves(item_code, serial_nos): + last_moves = {} + for start in range(0, len(serial_nos), SYNC_CHUNK_SIZE): + for row in get_last_bundle_moves_chunk(item_code, serial_nos[start : start + SYNC_CHUNK_SIZE]): + last_moves[row.serial_no] = row + + return last_moves + + +def get_last_bundle_moves_chunk(item_code, serial_nos): + """A bundle can be created much before its Stock Ledger Entry, so same-posting-datetime + ties are broken on the creation of the bundle's own SLE. The SLE join also keeps only + real stock movements - reservation bundles (Pick List) carry no SLE.""" + entry = frappe.qb.DocType("Serial and Batch Entry") + bundle = frappe.qb.DocType("Serial and Batch Bundle") + sle = frappe.qb.DocType("Stock Ledger Entry") + + row_number = ( + an.RowNumber() + .over(entry.serial_no) + .orderby(bundle.posting_datetime, order=Order.desc) + .orderby(sle.creation, order=Order.desc) + ) + + ranked = ( + frappe.qb.from_(entry) + .inner_join(bundle) + .on(entry.parent == bundle.name) + .inner_join(sle) + .on(sle.serial_and_batch_bundle == bundle.name) + .select( + entry.serial_no, + entry.qty, + Coalesce(entry.warehouse, bundle.warehouse).as_("warehouse"), + bundle.voucher_type, + bundle.voucher_no, + row_number.as_("row_no"), + ) + .where( + (bundle.docstatus == 1) + & (Coalesce(bundle.is_cancelled, 0) == 0) + & (sle.is_cancelled == 0) + & (bundle.item_code == item_code) + & (entry.serial_no.isin(serial_nos)) + ) + ).as_("ranked") + + return ( + frappe.qb.from_(ranked) + .select(ranked.serial_no, ranked.qty, ranked.warehouse, ranked.voucher_type, ranked.voucher_no) + .where(ranked.row_no == 1) + .run(as_dict=True) + ) + + +def set_legacy_last_moves(item_code, serial_nos, last_moves): + """Movements posted before Serial and Batch Bundle exist only as newline-separated + text on Stock Ledger Entry.""" + from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos + + pending = set(serial_nos) + rows = frappe.get_all( + "Stock Ledger Entry", + filters={"item_code": item_code, "is_cancelled": 0, "serial_no": ("is", "set")}, + fields=["serial_no", "actual_qty", "warehouse", "voucher_type", "voucher_no"], + order_by="posting_datetime asc, creation asc", + ) + + for row in rows: + qty = 1 if flt(row.actual_qty) > 0 else -1 + for serial_no in get_serial_nos(row.serial_no): + if serial_no in pending: + last_moves[serial_no] = frappe._dict( + qty=qty, + warehouse=row.warehouse, + voucher_type=row.voucher_type, + voucher_no=row.voucher_no, + ) diff --git a/erpnext/stock/report/stock_qty_vs_serial_no_count/test_stock_qty_vs_serial_no_count.py b/erpnext/stock/report/stock_qty_vs_serial_no_count/test_stock_qty_vs_serial_no_count.py new file mode 100644 index 00000000000..f61ed70ef72 --- /dev/null +++ b/erpnext/stock/report/stock_qty_vs_serial_no_count/test_stock_qty_vs_serial_no_count.py @@ -0,0 +1,41 @@ +# Copyright (c) 2026, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt + +import frappe +from frappe.tests.utils import FrappeTestCase + +from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry + + +class TestStockQtyVsSerialNoCount(FrappeTestCase): + def test_sync_serial_no_status(self): + from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note + from erpnext.stock.report.stock_qty_vs_serial_no_count.stock_qty_vs_serial_no_count import ( + sync_serial_no_status_for_warehouse, + ) + + item = "_Test Serialized Item With Series" + warehouse = "Stores - _TC" + se = make_stock_entry(item_code=item, to_warehouse=warehouse, qty=2, rate=100) + serial_no = frappe.get_all( + "Serial and Batch Entry", + {"parent": se.items[0].serial_and_batch_bundle}, + pluck="serial_no", + )[0] + + create_delivery_note( + item_code=item, + warehouse=warehouse, + qty=1, + serial_no=serial_no, + use_serial_batch_fields=1, + ) + self.assertEqual(frappe.db.get_value("Serial No", serial_no, "status"), "Delivered") + + frappe.db.set_value("Serial No", serial_no, {"status": "Active", "warehouse": warehouse}) + + sync_serial_no_status_for_warehouse(warehouse, item_code=item) + + details = frappe.db.get_value("Serial No", serial_no, ["status", "warehouse"], as_dict=True) + self.assertEqual(details.status, "Delivered") + self.assertFalse(details.warehouse) diff --git a/erpnext/templates/form_grid/includes/visible_cols.html b/erpnext/templates/form_grid/includes/visible_cols.html index 3a0cc8d7239..578335ddcd4 100644 --- a/erpnext/templates/form_grid/includes/visible_cols.html +++ b/erpnext/templates/form_grid/includes/visible_cols.html @@ -3,7 +3,7 @@ if((df.fieldname !== "description" && df.fieldname !== "item_name") && val) { %}
- {%= __(df.label) %}: + {%= frappe.utils.escape_html(__(df.label, null, df.parent)) %}:
{%= doc.get_formatted(df.fieldname) %} diff --git a/erpnext/templates/form_grid/item_grid.html b/erpnext/templates/form_grid/item_grid.html index 72db6c8e653..fac31c7c1a1 100644 --- a/erpnext/templates/form_grid/item_grid.html +++ b/erpnext/templates/form_grid/item_grid.html @@ -31,7 +31,7 @@ } %} - {%= doc.warehouse %} + {%= frappe.utils.escape_html(doc.warehouse) %} {% } %} @@ -42,14 +42,14 @@ doc.delivered_qty : doc.received_qty; var pending = flt(doc.qty) - flt(delivered); %} - {%= doc.item_code %} + {%= frappe.utils.escape_html(doc.item_code) %} {% } else { %} - {%= doc.item_code %} + {%= frappe.utils.escape_html(doc.item_code) %} {% } %} {% if(doc.item_name != doc.item_code && in_list(visible_column_fieldnames, "item_name")) { %} {% if (doc.item_code) { %}
{% } %} - {%= doc.item_name %}{% } %} + {%= frappe.utils.escape_html(doc.item_name) %}{% } %} {% include "templates/form_grid/includes/visible_cols.html" %}
@@ -57,7 +57,7 @@ @@ -84,7 +84,7 @@ {% if (frappe.perm.is_visible("rate", doc, frm.perm)) { %}
- {%= doc.get_formatted("qty") %} {%= doc.uom || doc.stock_uom %} + {%= doc.get_formatted("qty") %} {%= frappe.utils.escape_html(doc.uom || doc.stock_uom) %} x {%= doc.get_formatted("rate") %}
{% } %} diff --git a/erpnext/templates/form_grid/material_request_grid.html b/erpnext/templates/form_grid/material_request_grid.html index 866c06e5863..ff58da62ab5 100644 --- a/erpnext/templates/form_grid/material_request_grid.html +++ b/erpnext/templates/form_grid/material_request_grid.html @@ -11,9 +11,9 @@ {% } else { %}
- {%= doc.item_code %} + {%= frappe.utils.escape_html(doc.item_code) %} {% if(doc.item_name != doc.item_code) { %} -
{%= doc.item_name %}{% } %} +
{%= frappe.utils.escape_html(doc.item_name) %}{% } %} {% include "templates/form_grid/includes/visible_cols.html" %} @@ -35,7 +35,7 @@ {% if(doc.warehouse) { %} - {%= doc.warehouse %} + {%= frappe.utils.escape_html(doc.warehouse) %} {% } %}
@@ -43,7 +43,7 @@
{%= doc.get_formatted("qty") %} - {%= doc.uom || doc.stock_uom %} + {%= frappe.utils.escape_html(doc.uom || doc.stock_uom) %}
{% } %} diff --git a/erpnext/templates/form_grid/stock_entry_grid.html b/erpnext/templates/form_grid/stock_entry_grid.html index 8604881812d..d0afa926c50 100644 --- a/erpnext/templates/form_grid/stock_entry_grid.html +++ b/erpnext/templates/form_grid/stock_entry_grid.html @@ -12,9 +12,9 @@
{% } else { %}
-
{%= doc.item_code %} +
{%= frappe.utils.escape_html(doc.item_code) %} {% if(doc.item_name != doc.item_code) { %} -
{%= doc.item_name %}{% } %} +
{%= frappe.utils.escape_html(doc.item_name) %}{% } %} {% include "templates/form_grid/includes/visible_cols.html" %}
@@ -30,11 +30,11 @@ } %} - {%= doc.s_warehouse %} + {%= frappe.utils.escape_html(doc.s_warehouse) %} {% }; %} {% if(doc.t_warehouse) { %}
- {%= doc.t_warehouse %} + {%= frappe.utils.escape_html(doc.t_warehouse) %}
{% }; %}
@@ -42,7 +42,7 @@
{%= doc.get_formatted("qty") %} -
{%= doc.uom || doc.stock_uom %} +
{%= frappe.utils.escape_html(doc.uom || doc.stock_uom) %}
diff --git a/erpnext/templates/generators/sales_partner.html b/erpnext/templates/generators/sales_partner.html index 39138d3c6cc..0cd886f1ce7 100644 --- a/erpnext/templates/generators/sales_partner.html +++ b/erpnext/templates/generators/sales_partner.html @@ -9,16 +9,16 @@
{% if logo -%} - +

{%- endif %}
{% if partner_website -%}

{{ partner_website }}

{%- endif %} - {% if partner_address -%}

{{ partner_address }}

{%- endif %} - {% if phone -%}

{{ phone }}

{%- endif %} - {% if email -%}

{{ email }}

{%- endif %} + {% if partner_address -%}

{{ partner_address | e }}

{%- endif %} + {% if phone -%}

{{ phone | e }}

{%- endif %} + {% if email -%}

{{ email | e }}

{%- endif %}
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html index dc9ee234d9e..5945d487d29 100644 --- a/erpnext/templates/includes/macros.html +++ b/erpnext/templates/includes/macros.html @@ -2,7 +2,7 @@
{% endmacro %} @@ -10,7 +10,7 @@ {% macro product_image(website_image, css_class="product-image", alt="", no_border=False) %}
{% if website_image %} - {{ alt }} + {{ alt | e }} {% else %}
{{ frappe.utils.get_abbr(alt) or "NA" }} @@ -22,11 +22,11 @@ {% macro media_image(website_image, name, css_class="") %}
- {{ doc.project_name }} + {{ doc.project_name | e }}
{% if doc.percent_complete %} @@ -33,11 +33,11 @@ "full_name", "user_image" ], as_dict = True) %} {% if user_details.user_image %} - + {% else %} - +
{{ frappe.utils.get_abbr(user_details.full_name) }}
diff --git a/erpnext/templates/includes/projects/project_tasks.html b/erpnext/templates/includes/projects/project_tasks.html index 43fa591cd47..32719adf71d 100644 --- a/erpnext/templates/includes/projects/project_tasks.html +++ b/erpnext/templates/includes/projects/project_tasks.html @@ -8,7 +8,7 @@
{% endif %} - {{ task.subject }} + {{ task.subject | e }}
{{ task.status }}
@@ -26,11 +26,11 @@ ["full_name", "user_image"], as_dict = True)%} {% if user_details.user_image %} - + {% else %} - +
{{ frappe.utils.get_abbr(user_details.full_name) }}
diff --git a/erpnext/templates/includes/projects/project_timesheets.html b/erpnext/templates/includes/projects/project_timesheets.html index 6c3f8011ecd..8e118d2499c 100644 --- a/erpnext/templates/includes/projects/project_timesheets.html +++ b/erpnext/templates/includes/projects/project_timesheets.html @@ -14,11 +14,11 @@ ], as_dict = True) %} {% if user_details.user_image %} - + {% else %} - +
{{ frappe.utils.get_abbr(user_details.full_name) }}
diff --git a/erpnext/templates/includes/rfq.js b/erpnext/templates/includes/rfq.js index cc998a90030..6b76404d004 100644 --- a/erpnext/templates/includes/rfq.js +++ b/erpnext/templates/includes/rfq.js @@ -5,10 +5,10 @@ window.doc={{ doc.as_json() }}; $(document).ready(function() { new rfq(); - doc.supplier = "{{ doc.supplier }}" - doc.currency = "{{ doc.currency }}" - doc.number_format = "{{ doc.number_format }}" - doc.buying_price_list = "{{ doc.buying_price_list }}" + doc.supplier = {{ doc.supplier | tojson }} + doc.currency = {{ doc.currency | tojson }} + doc.number_format = {{ doc.number_format | tojson }} + doc.buying_price_list = {{ doc.buying_price_list | tojson }} }); rfq = class rfq { diff --git a/erpnext/templates/includes/transaction_row.html b/erpnext/templates/includes/transaction_row.html index 061c9bd1796..49524b92431 100644 --- a/erpnext/templates/includes/transaction_row.html +++ b/erpnext/templates/includes/transaction_row.html @@ -7,12 +7,14 @@ {{ frappe.utils.global_date_format(doc.modified) }}
-
- {{ _(doc.status) }} -
+ {% if doc.doctype != "Request for Quotation" %} +
+ {{ _(doc.status) }} +
+ {% endif %}
- {{ doc.items_preview }} + {{ doc.items_preview | e }}
{% if doc.is_rounded_total_disabled() and doc.get('grand_total') %} @@ -25,5 +27,5 @@
{% endif %}
- Link + Link
diff --git a/erpnext/templates/pages/help.html b/erpnext/templates/pages/help.html index 726d5e1b881..7e11bcb7d54 100644 --- a/erpnext/templates/pages/help.html +++ b/erpnext/templates/pages/help.html @@ -17,12 +17,12 @@ {% for section in get_started_sections %}
-

{{ section["name"] }}

+

{{ section["name"] | e }}

{% for item in section["items"] %}
- {{ item.title }} + {{ item.title | e }} {% if item.description -%} -

{{ item.description }}

+

{{ item.description | e }}

{%- endif %}
{% endfor %} @@ -35,15 +35,15 @@

{{ _("Forum Activity") }}

{% for topic in topics %}
- - {{ topic[post_params.title] }} + + {{ topic[post_params.title] | e }} {% if topic[post_params.description] -%} -

{{ topic[post_params.description] }}

+

{{ topic[post_params.description] | e }}

{%- endif %}
{% endfor %} -

{{ _("Visit the forums") }}

+

{{ _("Visit the forums") }}


diff --git a/erpnext/templates/pages/order.html b/erpnext/templates/pages/order.html index 5563a58b730..ec9d75e350a 100644 --- a/erpnext/templates/pages/order.html +++ b/erpnext/templates/pages/order.html @@ -73,11 +73,11 @@
{%- set party_name = doc.supplier_name if doc.doctype in ['Supplier Quotation', 'Purchase Invoice', 'Purchase Order'] else doc.customer_name %} - {{ party_name }} + {{ party_name | e }} {% if doc.contact_display and doc.contact_display != party_name %}
- {{ doc.contact_display }} + {{ doc.contact_display | e }} {% endif %}
@@ -151,7 +151,7 @@ {% if doc.terms %}

-

{{ doc.terms }}

+

{{ frappe.sanitize_html(doc.terms) }}

{% endif %} {% endblock %} diff --git a/erpnext/templates/pages/partners.html b/erpnext/templates/pages/partners.html index 72d6a6478f7..5b6ae2c5670 100644 --- a/erpnext/templates/pages/partners.html +++ b/erpnext/templates/pages/partners.html @@ -10,18 +10,18 @@
{% if partner_info.logo -%} - - + + {%- endif %}
- +

{{ partner_info.partner_name }}

{{ partner_info.territory }} - {{ partner_info.partner_type }}

-

{{ partner_info.introduction }}

+

{{ partner_info.introduction | e }}


diff --git a/erpnext/templates/pages/projects.html b/erpnext/templates/pages/projects.html index e671e91db2f..2b55679fa71 100644 --- a/erpnext/templates/pages/projects.html +++ b/erpnext/templates/pages/projects.html @@ -1,7 +1,7 @@ {% extends "templates/web.html" %} {% block title %} - {{ doc.project_name }} + {{ doc.project_name | e }} {% endblock %} {% block head_include %} @@ -9,7 +9,7 @@ {% endblock %} {% block header %} -

{{ doc.project_name }}

+

{{ doc.project_name | e }}

{% endblock %} {% block style %} @@ -34,7 +34,7 @@

{{ _("Tasks") }}

- {{ _("New task") }} + {{ _("New task") }}
{% if doc.tasks %} diff --git a/erpnext/templates/pages/projects.js b/erpnext/templates/pages/projects.js index 622ed42f85f..bf037bcf6a5 100644 --- a/erpnext/templates/pages/projects.js +++ b/erpnext/templates/pages/projects.js @@ -45,7 +45,7 @@ frappe.ready(function () { dataType: "json", data: { cmd: "erpnext.templates.pages.projects.get_" + item + "_html", - project: "{{ doc.name }}", + project: frappe.utils.get_url_arg("project"), item_status: item_status, }, success: function (data) { @@ -80,7 +80,7 @@ frappe.ready(function () { dataType: "json", data: { cmd: "erpnext.templates.pages.projects.get_" + item + "_html", - project: "{{ doc.name }}", + project: frappe.utils.get_url_arg("project"), start: start, item_status: item_status, }, @@ -96,7 +96,7 @@ frappe.ready(function () { var close_item = function (item, item_name) { var args = { - project: "{{ doc.name }}", + project: frappe.utils.get_url_arg("project"), item_name: item_name, }; frappe.call({ diff --git a/erpnext/templates/pages/rfq.html b/erpnext/templates/pages/rfq.html index d371bf2161d..d2a9382dc6b 100644 --- a/erpnext/templates/pages/rfq.html +++ b/erpnext/templates/pages/rfq.html @@ -13,7 +13,7 @@ {% endblock %} {% block header_actions %} -{% if doc.items %} +{% if doc.items and not doc.rfq_links %} @@ -22,10 +22,7 @@ {% block page_content %}
-
-
{{ doc.supplier }}
-
-
+
{{ doc.get_formatted("transaction_date") }}
diff --git a/erpnext/templates/print_formats/includes/item_table_description.html b/erpnext/templates/print_formats/includes/item_table_description.html index 7569e50b45c..4ad3d6dd1d1 100644 --- a/erpnext/templates/print_formats/includes/item_table_description.html +++ b/erpnext/templates/print_formats/includes/item_table_description.html @@ -5,7 +5,7 @@ {% if doc.in_format_data("image") and doc.get("image") and "image" in display_columns -%}
- +
{%- endif %} diff --git a/erpnext/www/support/index.html b/erpnext/www/support/index.html index 3c19198cc16..d2625cd55ad 100644 --- a/erpnext/www/support/index.html +++ b/erpnext/www/support/index.html @@ -49,11 +49,11 @@
- {{ favorite_article['category'] }}
-

{{ favorite_article['title'] }}

-

{{ favorite_article['description'] }}

+ {{ favorite_article['category'] | e }} +

{{ favorite_article['title'] | e }}

+

{{ favorite_article['description'] | e }}

- +
{% endfor %} @@ -72,7 +72,7 @@
{{ item['category'].name }}
{% for article in item['articles'] %} - {{ article.title }} + {{ article.title | e }} {% endfor %}