POST to /invoices not creating invoice with expected properties

I’m trying to create invoices via the REST API. I have properties such as Total (excl. tax) (f.total_ht) and Invoice ref.* (f.ref), however on invoice creation, these properties don’t seem to have been applied correctly in the newly created invoice.

An example request object looks like this:

  {
    "mode_reglement_id": "6",
    "cond_reglement_id": "1",
    "multicurrency_tx": "1.00000000",
    "model_pdf": "sponge",
    "fk_account": "3",
    "total_tva": "0.00000000",
    "total_localtax1": "0.00000000",
    "total_localtax2": "0.00000000",
    "lines": [
      {
        "array_options": [],
        "total_tva": "0.00000000",
        "total_localtax1": "0.00000000",
        "total_localtax2": "0.00000000",
        "nb": [],
        "extraparams": [],
        "product_type": "0",
        "fk_product": 1,
        "product_barcode": null,
        "product_desc": "",
        "fk_product_type": "0",
        "qty": 1,
        "remise_percent": "0",
        "info_bits": "0",
        "special_code": "0",
        "tva_tx": "0.0000",
        "localtax1_tx": "0.0000",
        "localtax2_tx": "0.0000",
        "pa_ht": "0.00000000",
        "multicurrency_subprice": "0.00000000",
        "multicurrency_total_ht": "0.00000000",
        "multicurrency_total_tva": "0.00000000",
        "multicurrency_total_ttc": "0.00000000",
        "fk_accounting_account": "0",
        "rang": "0",
        "fk_code_ventilation": 0,
        "situation_percent": "100",
        "code_ventilation": "0",
        "fk_facture": "VQ58317546",
        "description": "Original Chicken Biscuit $370.0",
        "desc": "Original Chicken Biscuit $370.0",
        "total_ttc": "370",
        "total_ht": "370",
        "date_start": 1701058523,
        "date_end": 1701058523
      },
      {
        "array_options": [],
        "total_tva": "0.00000000",
        "total_localtax1": "0.00000000",
        "total_localtax2": "0.00000000",
        "nb": [],
        "extraparams": [],
        "product_type": "0",
        "fk_product": 1,
        "product_barcode": null,
        "product_desc": "",
        "fk_product_type": "0",
        "qty": 1,
        "remise_percent": "0",
        "info_bits": "0",
        "special_code": "0",
        "tva_tx": "0.0000",
        "localtax1_tx": "0.0000",
        "localtax2_tx": "0.0000",
        "pa_ht": "0.00000000",
        "multicurrency_subprice": "0.00000000",
        "multicurrency_total_ht": "0.00000000",
        "multicurrency_total_tva": "0.00000000",
        "multicurrency_total_ttc": "0.00000000",
        "fk_accounting_account": "0",
        "rang": "0",
        "fk_code_ventilation": 0,
        "situation_percent": "100",
        "code_ventilation": "0",
        "fk_facture": "VQ58317546",
        "description": "Original Chicken Biscuit $340.0",
        "desc": "Original Chicken Biscuit $340.0",
        "total_ttc": "340",
        "total_ht": "340",
        "date_start": 1701058523,
        "date_end": 1701058523
      }
    ],
    "user_author": "4",
    "specimen": 0,
    "nb": [],
    "extraparams": [],
    "type": "0",
    "remaintopay": "0",
    "fk_user_author": "4",
    "remise_absolue": "0",
    "remise_percent": "0",
    "revenuestamp": "0.00000000",
    "paye": "1",
    "cond_reglement_code": "RECEP",
    "cond_reglement_doc": "Due upon receipt",
    "mode_reglement_code": "CB",
    "date_pointoftax": "",
    "multicurrency_total_ht": "0.00000000",
    "multicurrency_total_tva": "0.00000000",
    "multicurrency_total_ttc": "0.00000000",
    "tab_previous_situation_invoice": [],
    "tab_next_situation_invoice": [],
    "ref": "VQ58317546",
    "ref_ext": "VQ58317546",
    "socid": 14,
    "date": 1701058523,
    "datem": 1701058523,
    "date_lim_reglement": 1701058523,
    "date_validation": 1701058523,
    "sumpayed": "0",
    "total_ttc": "710",
    "total_ht": "710",
    "totalpaid": "710",
    "sumpaid": "710",
    "status": "1",
    "statut": "1",
    "": "1"
  }

And in CURL it looks like (with authentication stripped):

curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'DOLAPIKEY: ' -d ' \ 
   { \ 
     "mode_reglement_id": "6", \ 
     "cond_reglement_id": "1", \ 
     "multicurrency_tx": "1.00000000", \ 
     "model_pdf": "sponge", \ 
     "fk_account": "3", \ 
     "total_tva": "0.00000000", \ 
     "total_localtax1": "0.00000000", \ 
     "total_localtax2": "0.00000000", \ 
     "lines": [ \ 
       { \ 
         "array_options": [], \ 
         "total_tva": "0.00000000", \ 
         "total_localtax1": "0.00000000", \ 
         "total_localtax2": "0.00000000", \ 
         "nb": [], \ 
         "extraparams": [], \ 
         "product_type": "0", \ 
         "fk_product": 1, \ 
         "product_barcode": null, \ 
         "product_desc": "", \ 
         "fk_product_type": "0", \ 
         "qty": 1, \ 
         "remise_percent": "0", \ 
         "info_bits": "0", \ 
         "special_code": "0", \ 
         "tva_tx": "0.0000", \ 
         "localtax1_tx": "0.0000", \ 
         "localtax2_tx": "0.0000", \ 
         "pa_ht": "0.00000000", \ 
         "multicurrency_subprice": "0.00000000", \ 
         "multicurrency_total_ht": "0.00000000", \ 
         "multicurrency_total_tva": "0.00000000", \ 
         "multicurrency_total_ttc": "0.00000000", \ 
         "fk_accounting_account": "0", \ 
         "rang": "0", \ 
         "fk_code_ventilation": 0, \ 
         "situation_percent": "100", \ 
         "code_ventilation": "0", \ 
         "fk_facture": "VQ58317546", \ 
         "description": "Original Chicken Biscuit $370.0", \ 
         "desc": "Original Chicken Biscuit $370.0", \ 
         "total_ttc": "370", \ 
         "total_ht": "370", \ 
         "date_start": 1701058523, \ 
         "date_end": 1701058523 \ 
       }, \ 
       { \ 
         "array_options": [], \ 
         "total_tva": "0.00000000", \ 
         "total_localtax1": "0.00000000", \ 
         "total_localtax2": "0.00000000", \ 
         "nb": [], \ 
         "extraparams": [], \ 
         "product_type": "0", \ 
         "fk_product": 1, \ 
         "product_barcode": null, \ 
         "product_desc": "", \ 
         "fk_product_type": "0", \ 
         "qty": 1, \ 
         "remise_percent": "0", \ 
         "info_bits": "0", \ 
         "special_code": "0", \ 
         "tva_tx": "0.0000", \ 
         "localtax1_tx": "0.0000", \ 
         "localtax2_tx": "0.0000", \ 
         "pa_ht": "0.00000000", \ 
         "multicurrency_subprice": "0.00000000", \ 
         "multicurrency_total_ht": "0.00000000", \ 
         "multicurrency_total_tva": "0.00000000", \ 
         "multicurrency_total_ttc": "0.00000000", \ 
         "fk_accounting_account": "0", \ 
         "rang": "0", \ 
         "fk_code_ventilation": 0, \ 
         "situation_percent": "100", \ 
         "code_ventilation": "0", \ 
         "fk_facture": "VQ58317546", \ 
         "description": "Original Chicken Biscuit $340.0", \ 
         "desc": "Original Chicken Biscuit $340.0", \ 
         "total_ttc": "340", \ 
         "total_ht": "340", \ 
         "date_start": 1701058523, \ 
         "date_end": 1701058523 \ 
       } \ 
     ], \ 
     "user_author": "4", \ 
     "specimen": 0, \ 
     "nb": [], \ 
     "extraparams": [], \ 
     "type": "0", \ 
     "remaintopay": "0", \ 
     "fk_user_author": "4", \ 
     "remise_absolue": "0", \ 
     "remise_percent": "0", \ 
     "revenuestamp": "0.00000000", \ 
     "paye": "1", \ 
     "cond_reglement_code": "RECEP", \ 
     "cond_reglement_doc": "Due upon receipt", \ 
     "mode_reglement_code": "CB", \ 
     "date_pointoftax": "", \ 
     "multicurrency_total_ht": "0.00000000", \ 
     "multicurrency_total_tva": "0.00000000", \ 
     "multicurrency_total_ttc": "0.00000000", \ 
     "tab_previous_situation_invoice": [], \ 
     "tab_next_situation_invoice": [], \ 
     "ref": "VQ58317546", \ 
     "ref_ext": "VQ58317546", \ 
     "socid": 14, \ 
     "date": 1701058523, \ 
     "datem": 1701058523, \ 
     "date_lim_reglement": 1701058523, \ 
     "date_validation": 1701058523, \ 
     "sumpayed": "0", \ 
     "total_ttc": "710", \ 
     "total_ht": "710", \ 
     "totalpaid": "710", \ 
     "sumpaid": "710", \ 
     "status": "1", \ 
     "statut": "1", \ 
     "": "1" \ 
   } \ 
  \ 
 ' 'example.com'

How can I get these properties to apply to the newly created invoice? Is there some other key name I should be using?

I suspected perhaps the totals needed the arbitrary formats for floats, so I tried this request object:

{
        "mode_reglement_id": 4,
        "model_pdf": "sponge",
        "fk_account": "3",
        "lines": [],
        "fk_user_author": "4",
        "remise_absolue": "0",
        "remise_percent": "0",
        "revenuestamp": "0.00000000",
        "cond_reglement_code": "RECEP",
        "cond_reglement_doc": "Due upon receipt",
        "mode_reglement_code": "CB",
        "ref": "VQ58317546",
        "ref_ext": "VQ58317546",
        "socid": 14,
        "date": 1701058523,
        "datem": 1701058523,
        "date_lim_reglement": 1701058523,
        "date_validation": 1701058523,
        "sumpayed": "710.00000000",
        "paye": "1",
        "total_ttc": "710.00000000",
        "total_ht": "710.00000000",
        "totalpaid": "710.00000000",
        "sumpaid": "710.00000000",
        "status": "1",
        "statut": "1"
    }

However that still didn’t work

Weirdly, I appear to be able to update ref on PATCH and it correctly updates.

I tried granting the API user full permissions, it had no effect.

I believe this file is relevant: https://github.com/ATM-Marc/dolibarr/blob/2fd3eb8bdf2f2810d117915cecb14f210ef5783c/htdocs/compta/facture/class/facture.class.php

oh actually this file and line seems more relevant https://github.com/Dolibarr/dolibarr/blob/develop/htdocs/compta/facture/class/api_invoices.class.php

I’ve been plugging away at this for a week with various CURLs but still haven’t sorted this unfortunately, going to delve into the code later and try debugging, but could use tips if anyone has experience in this area

Crosspost issue to github /Dolibarr/dolibarr/issues/26875

I switched on debug logging. From this, I can see that the SQL command issued has all price values set to 0

2024-03-19 12:38:22 DEBUG 123.193.242.33 sql=INSERT INTO llx_facturedet (fk_facture, fk_parent_line, label, description, qty, vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, fk_product, product_type, remise_percent, subprice, ref_ext, fk_remise_except, date_start, date_end, fk_code_ventilation, rang, special_code, fk_product_fournisseur_price, buy_price_ht, info_bits, total_ht, total_tva, total_ttc, total_localtax1, total_localtax2, situation_percent, fk_prev_id, fk_unit, fk_user_author, fk_user_modif, fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc) VALUES (906, null, null, 'Original Chicken Biscuit $340.0', 1, '', 0, 0, 0, '0', '0', 1, 0, 0, 0, '', null, '2023-11-27 04:15:23', '2023-11-27 04:15:23', 0, 0, 0, null, 0, '0', 0, 0, 0, 0, 0, 100, null, NULL, 4, 4, 0, 'TWD', 0, 0, 0, 0)

I believe this is the debug log for a whole transaction:

2024-03-19 12:38:22 NOTICE     sql=SELECT transkey, transvalue FROM llx_overwrite_trans where (lang='en_US' OR lang IS NULL) AND entity IN (0, 0,1) ORDER BY lang DESC
2024-03-19 12:38:22 INFO       Load a dedicated API file moduleobject=invoices moduledirforclass=compta/facture
2024-03-19 12:38:22 INFO       Search api file /compta/facture/class/api_invoices.class.php => dir_part_file=/var/www/html/compta/facture/class/api_invoices.class.php classname=Invoices
2024-03-19 12:38:22 DEBUG      sql=SELECT u.login, u.datec, u.api_key, u.tms as date_modification, u.entity FROM llx_user as u WHERE u.api_key = 'KEY' OR u.api_key = ''
2024-03-19 12:38:22 DEBUG      sql=SELECT u.rowid, u.lastname, u.firstname, u.employee, u.gender, u.civility as civility_code, u.birth, u.email, u.personal_email, u.job, u.socialnetworks, u.signature, u.office_phone, u.office_fax, u.user_mobile, u.personal_mobile, u.address, u.zip, u.town, u.fk_state as state_id, u.fk_country as country_id, u.admin, u.login, u.note_private, u.note_public, u.pass, u.pass_crypted, u.pass_temp, u.api_key, u.fk_soc, u.fk_socpeople, u.fk_member, u.fk_user, u.ldap_sid, u.fk_user_expense_validator, u.fk_user_holiday_validator, u.statut as status, u.lang, u.entity, u.datec as datec, u.tms as datem, u.datelastlogin as datel, u.datepreviouslogin as datep, u.flagdelsessionsbefore, u.iplastlogin, u.ippreviouslogin, u.datelastpassvalidation, u.datestartvalidity, u.dateendvalidity, u.photo as photo, u.openid as openid, u.accountancy_code, u.thm, u.tjm, u.salary, u.salaryextra, u.weeklyhours, u.color, u.dateemployment, u.dateemploymentend, u.fk_warehouse, u.ref_ext, u.default_range, u.default_c_exp_tax_cat, u.national_registration_number, u.ref_employee, c.code as country_code, c.label as country, d.code_departement as state_code, d.nom as state FROM llx_user as u LEFT JOIN llx_c_country as c ON u.fk_country = c.rowid LEFT JOIN llx_c_departements as d ON u.fk_state = d.rowid WHERE u.entity IN (0, 1) AND u.login = 'caleb' ORDER BY u.entity ASC
2024-03-19 12:38:22 DEBUG      sql=SELECT rowid, name, label, type, size, elementtype, fieldunique, fieldrequired, param, pos, alwayseditable, perms, langs, list, printable, totalizable, fielddefault, fieldcomputed, entity, enabled, help, css, cssview, csslist FROM llx_extrafields WHERE elementtype = 'user' ORDER BY pos
2024-03-19 12:38:22 DEBUG      sql=SELECT DISTINCT r.module, r.perms, r.subperms FROM llx_user_rights as ur, llx_rights_def as r WHERE r.id = ur.fk_id AND r.entity = 1 AND ur.entity = 1 AND ur.fk_user= 4 AND r.perms IS NOT NULL AND r.perms NOT LIKE '%_advance'
2024-03-19 12:38:22 DEBUG      sql=SELECT DISTINCT r.module, r.perms, r.subperms FROM llx_usergroup_rights as gr, llx_usergroup_user as gu, llx_rights_def as r WHERE r.id = gr.fk_id AND gr.entity = 1 AND gu.entity IN (0,1) AND r.entity = 1 AND gr.fk_usergroup = gu.fk_usergroup AND gu.fk_user = 4 AND r.perms IS NOT NULL
2024-03-19 12:38:22 INFO       Facture::create user=4 date=1701058523
2024-03-19 12:38:22 DEBUG      sql=SELECT s.rowid, s.nom as name, s.name_alias, s.entity, s.ref_ext, s.address, s.datec as date_creation, s.prefix_comm, s.status, s.fk_warehouse, s.price_level, s.tms as date_modification, s.fk_user_creat, s.fk_user_modif, s.phone, s.fax, s.email, s.socialnetworks, s.url, s.zip, s.town, s.note_private, s.note_public, s.client, s.fournisseur, s.siren as idprof1, s.siret as idprof2, s.ape as idprof3, s.idprof4, s.idprof5, s.idprof6, s.capital, s.tva_intra, s.fk_typent as typent_id, s.fk_effectif as effectif_id, s.fk_forme_juridique as forme_juridique_code, s.webservices_url, s.webservices_key, s.model_pdf, s.last_main_doc, s.code_compta, s.code_compta_fournisseur, s.accountancy_code_buy, s.accountancy_code_sell, s.vat_reverse_charge as soc_vat_reverse_charge, s.code_client, s.code_fournisseur, s.parent, s.barcode, s.fk_departement as state_id, s.fk_pays as country_id, s.fk_stcomm, s.mode_reglement, s.cond_reglement, s.deposit_percent, s.transport_mode, s.fk_account, s.tva_assuj, s.mode_reglement_supplier, s.cond_reglement_supplier, s.transport_mode_supplier, s.localtax1_assuj, s.localtax1_value, s.localtax2_assuj, s.localtax2_value, s.fk_prospectlevel, s.default_lang, s.logo, s.logo_squarred, s.fk_shipping_method, s.outstanding_limit, s.import_key, s.canvas, s.fk_incoterms, s.location_incoterms, s.order_min_amount, s.supplier_order_min_amount, s.fk_multicurrency, s.multicurrency_code, fj.libelle as forme_juridique, e.libelle as effectif, c.code as country_code, c.label as country, d.code_departement as state_code, d.nom as state, r.rowid as region_id, r.code_region as region_code, st.libelle as stcomm, st.picto as stcomm_picto, te.code as typent_code, i.libelle as label_incoterms, s.remise_client, s.remise_supplier FROM llx_societe as s LEFT JOIN llx_c_effectif as e ON s.fk_effectif = e.id LEFT JOIN llx_c_country as c ON s.fk_pays = c.rowid LEFT JOIN llx_c_stcomm as st ON s.fk_stcomm = st.id LEFT JOIN llx_c_forme_juridique as fj ON s.fk_forme_juridique = fj.code LEFT JOIN llx_c_departements as d ON s.fk_departement = d.rowid LEFT JOIN llx_c_regions as r ON d.fk_region = r.code_region  LEFT JOIN llx_c_typent as te ON s.fk_typent = te.id LEFT JOIN llx_c_incoterms as i ON s.fk_incoterms = i.rowid WHERE s.entity IN (1) AND s.rowid = 14
2024-03-19 12:38:22 DEBUG      sql=SELECT rowid, name, label, type, size, elementtype, fieldunique, fieldrequired, param, pos, alwayseditable, perms, langs, list, printable, totalizable, fielddefault, fieldcomputed, entity, enabled, help, css, cssview, csslist FROM llx_extrafields WHERE elementtype = 'societe' ORDER BY pos
2024-03-19 12:38:22 DEBUG      BEGIN Transaction
2024-03-19 12:38:22 DEBUG       sql=INSERT INTO llx_facture ( ref, entity, ref_ext, type, fk_soc, datec, remise_absolue, remise_percent, datef, date_pointoftax, note_private, note_public, ref_client, fk_account, module_source, pos_source, fk_fac_rec_source, fk_facture_source, fk_user_author, fk_projet, fk_cond_reglement, fk_mode_reglement, date_lim_reglement, model_pdf, situation_cycle_ref, situation_counter, situation_final, fk_incoterms, location_incoterms, fk_multicurrency, multicurrency_code, multicurrency_tx, retained_warranty, retained_warranty_date_limit, retained_warranty_fk_cond_reglement) VALUES ('(PROV)', 1, 'VQ58317546', '0', 14, '2024-03-19 12:38:22', NULL, NULL, '2023-11-27 04:15:23', null, null, null, null, 3, null, null, null, null, 4, null, 0, 4, '2023-11-27 04:15:23', 'sponge', null, null, 0, 0, '', 0, 'TWD', 1, 0, NULL, 0)
2024-03-19 12:38:22 DEBUG       sql=UPDATE llx_facture SET ref='(PROV906)' WHERE rowid=906
2024-03-19 12:38:22 INFO        There is 2 lines that are array lines
2024-03-19 12:38:22 DEBUG       Facture::addline id=906, pu_ht=, qty=1, txtva=, txlocaltax1=, txlocaltax2=, fk_product=1, remise_percent=, date_start=1701058523, date_end=1701058523, ventil=, info_bits=, fk_remise_except=, price_base_type=HT, pu_ttc=0, type=, fk_unit=, desc=Original Chicken Biscuit …
2024-03-19 12:38:22 INFO         Product::fetch id=1 ref= ref_ext=
2024-03-19 12:38:22 DEBUG        sql=SELECT p.rowid, p.ref, p.ref_ext, p.label, p.description, p.url, p.note_public, p.note as note_private, p.customcode, p.fk_country, p.fk_state, p.lifetime, p.qc_frequency, p.price, p.price_ttc, p.price_min, p.price_min_ttc, p.price_base_type, p.cost_price, p.default_vat_code, p.tva_tx, p.recuperableonly as tva_npr, p.localtax1_tx, p.localtax2_tx, p.localtax1_type, p.localtax2_type, p.tosell, p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.fk_default_workstation, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished, p.fk_default_bom, p.mandatory_period, p.accountancy_code_buy, p.accountancy_code_buy_intra, p.accountancy_code_buy_export, p.accountancy_code_sell, p.accountancy_code_sell_intra, p.accountancy_code_sell_export, p.pmp, p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.batch_mask, p.fk_unit, p.fk_price_expression, p.price_autogen, p.model_pdf, p.stock FROM llx_product as p WHERE p.rowid = 1
2024-03-19 12:38:22 DEBUG        sql=SELECT rowid, name, label, type, size, elementtype, fieldunique, fieldrequired, param, pos, alwayseditable, perms, langs, list, printable, totalizable, fielddefault, fieldcomputed, entity, enabled, help, css, cssview, csslist FROM llx_extrafields WHERE elementtype = 'product' ORDER BY pos
2024-03-19 12:38:22 DEBUG        sql=SELECT rowid, monitor, tipo_plato FROM llx_product_extrafields WHERE fk_object = 1
2024-03-19 12:38:22 INFO         getLocalTaxesFromRate vatrate=0 local=0
2024-03-19 12:38:22 DEBUG        sql=SELECT t.taux as rate, t.code, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.accountancy_code_sell, t.accountancy_code_buy FROM llx_c_tva as t, llx_c_country as c WHERE t.fk_pays = c.rowid AND c.code = 'TW' AND t.taux = 0 AND t.active = 1
2024-03-19 12:38:22 INFO         get_localtax tva=0 local=1 thirdparty_buyer id=/country_code= thirdparty_seller id=0/country_code=TW thirdparty_seller localtax1_assuj=0  thirdparty_seller localtax2_assuj=0
2024-03-19 12:38:22 INFO         get_localtax tva=0 local=2 thirdparty_buyer id=/country_code= thirdparty_seller id=0/country_code=TW thirdparty_seller localtax1_assuj=0  thirdparty_seller localtax2_assuj=0
2024-03-19 12:38:22 INFO         Price.lib::calcul_price_total qty=1 pu= remise_percent_ligne=0 txtva=0 uselocaltax1_rate=0 uselocaltax2_rate=0 remise_percent_global=0 price_base_type=HT type=0 progress=100
2024-03-19 12:38:22 INFO         Price.lib::calcul_price_total MAIN_ROUNDING_RULE_TOT= pu=0 qty=1 price_base_type=HT total_ht=0-total_vat=0-total_ttc=0
2024-03-19 12:38:22 DEBUG        FactureLigne::insert rang=0
2024-03-19 12:38:22 INFO         Product::fetch id=1 ref= ref_ext=
2024-03-19 12:38:22 DEBUG        sql=SELECT p.rowid, p.ref, p.ref_ext, p.label, p.description, p.url, p.note_public, p.note as note_private, p.customcode, p.fk_country, p.fk_state, p.lifetime, p.qc_frequency, p.price, p.price_ttc, p.price_min, p.price_min_ttc, p.price_base_type, p.cost_price, p.default_vat_code, p.tva_tx, p.recuperableonly as tva_npr, p.localtax1_tx, p.localtax2_tx, p.localtax1_type, p.localtax2_type, p.tosell, p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.fk_default_workstation, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished, p.fk_default_bom, p.mandatory_period, p.accountancy_code_buy, p.accountancy_code_buy_intra, p.accountancy_code_buy_export, p.accountancy_code_sell, p.accountancy_code_sell_intra, p.accountancy_code_sell_export, p.pmp, p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.batch_mask, p.fk_unit, p.fk_price_expression, p.price_autogen, p.model_pdf, p.stock FROM llx_product as p WHERE p.rowid = 1
2024-03-19 12:38:22 DEBUG        sql=SELECT rowid, monitor, tipo_plato FROM llx_product_extrafields WHERE fk_object = 1
2024-03-19 12:38:22 DEBUG        ProductFournisseur::find_min_price_product_fournisseur
2024-03-19 12:38:22 DEBUG        sql=SELECT s.nom as supplier_name, s.rowid as fourn_id, pfp.rowid as product_fourn_price_id, pfp.ref_fourn, pfp.price, pfp.quantity, pfp.unitprice, pfp.tva_tx, pfp.charges, pfp.remise, pfp.remise_percent, pfp.fk_supplier_price_expression, pfp.delivery_time_days ,pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code FROM llx_societe as s, llx_product_fournisseur_price as pfp WHERE s.entity IN (1) AND pfp.entity IN (1) AND pfp.fk_product = 1 AND pfp.fk_soc = s.rowid AND s.status = 1
2024-03-19 12:38:22 DEBUG        CommonObject::isExistingObject
2024-03-19 12:38:22 DEBUG        sql=SELECT rowid, ref, ref_ext FROM llx_product WHERE entity IN (1) AND rowid = 1
2024-03-19 12:38:22 DEBUG         FactureLigne::insert
2024-03-19 12:38:22 DEBUG         sql=INSERT INTO llx_facturedet (fk_facture, fk_parent_line, label, description, qty, vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, fk_product, product_type, remise_percent, subprice, ref_ext, fk_remise_except, date_start, date_end, fk_code_ventilation,  rang, special_code, fk_product_fournisseur_price, buy_price_ht, info_bits, total_ht, total_tva, total_ttc, total_localtax1, total_localtax2, situation_percent, fk_prev_id, fk_unit, fk_user_author, fk_user_modif, fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc) VALUES (906, null, null, 'Original Chicken Biscuit $370.0', 1, '', 0, 0, 0, '0', '0', 1, 0, 0, 0, '', null, '2023-11-27 04:15:23', '2023-11-27 04:15:23', 0, 0, 0, null, 0, '0', 0, 0, 0, 0, 0, 100, null, NULL, 4, 4, 0, 'TWD', 0, 0, 0, 0)
2024-03-19 12:38:22 DEBUG       Facture::addline id=906, pu_ht=, qty=1, txtva=, txlocaltax1=, txlocaltax2=, fk_product=1, remise_percent=, date_start=1701058523, date_end=1701058523, ventil=, info_bits=, fk_remise_except=, price_base_type=HT, pu_ttc=0, type=, fk_unit=, desc=Original Chicken Biscuit …
2024-03-19 12:38:22 INFO         Product::fetch id=1 ref= ref_ext=
2024-03-19 12:38:22 DEBUG        sql=SELECT p.rowid, p.ref, p.ref_ext, p.label, p.description, p.url, p.note_public, p.note as note_private, p.customcode, p.fk_country, p.fk_state, p.lifetime, p.qc_frequency, p.price, p.price_ttc, p.price_min, p.price_min_ttc, p.price_base_type, p.cost_price, p.default_vat_code, p.tva_tx, p.recuperableonly as tva_npr, p.localtax1_tx, p.localtax2_tx, p.localtax1_type, p.localtax2_type, p.tosell, p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.fk_default_workstation, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished, p.fk_default_bom, p.mandatory_period, p.accountancy_code_buy, p.accountancy_code_buy_intra, p.accountancy_code_buy_export, p.accountancy_code_sell, p.accountancy_code_sell_intra, p.accountancy_code_sell_export, p.pmp, p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.batch_mask, p.fk_unit, p.fk_price_expression, p.price_autogen, p.model_pdf, p.stock FROM llx_product as p WHERE p.rowid = 1
2024-03-19 12:38:22 DEBUG        sql=SELECT rowid, monitor, tipo_plato FROM llx_product_extrafields WHERE fk_object = 1
2024-03-19 12:38:22 INFO         getLocalTaxesFromRate vatrate=0 local=0
2024-03-19 12:38:22 DEBUG        sql=SELECT t.taux as rate, t.code, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.accountancy_code_sell, t.accountancy_code_buy FROM llx_c_tva as t, llx_c_country as c WHERE t.fk_pays = c.rowid AND c.code = 'TW' AND t.taux = 0 AND t.active = 1
2024-03-19 12:38:22 INFO         get_localtax tva=0 local=1 thirdparty_buyer id=/country_code= thirdparty_seller id=0/country_code=TW thirdparty_seller localtax1_assuj=0  thirdparty_seller localtax2_assuj=0
2024-03-19 12:38:22 INFO         get_localtax tva=0 local=2 thirdparty_buyer id=/country_code= thirdparty_seller id=0/country_code=TW thirdparty_seller localtax1_assuj=0  thirdparty_seller localtax2_assuj=0
2024-03-19 12:38:22 INFO         Price.lib::calcul_price_total qty=1 pu= remise_percent_ligne=0 txtva=0 uselocaltax1_rate=0 uselocaltax2_rate=0 remise_percent_global=0 price_base_type=HT type=0 progress=100
2024-03-19 12:38:22 INFO         Price.lib::calcul_price_total MAIN_ROUNDING_RULE_TOT= pu=0 qty=1 price_base_type=HT total_ht=0-total_vat=0-total_ttc=0
2024-03-19 12:38:22 DEBUG        FactureLigne::insert rang=0
2024-03-19 12:38:22 INFO         Product::fetch id=1 ref= ref_ext=
2024-03-19 12:38:22 DEBUG        sql=SELECT p.rowid, p.ref, p.ref_ext, p.label, p.description, p.url, p.note_public, p.note as note_private, p.customcode, p.fk_country, p.fk_state, p.lifetime, p.qc_frequency, p.price, p.price_ttc, p.price_min, p.price_min_ttc, p.price_base_type, p.cost_price, p.default_vat_code, p.tva_tx, p.recuperableonly as tva_npr, p.localtax1_tx, p.localtax2_tx, p.localtax1_type, p.localtax2_type, p.tosell, p.tobuy, p.fk_product_type, p.duration, p.fk_default_warehouse, p.fk_default_workstation, p.seuil_stock_alerte, p.canvas, p.net_measure, p.net_measure_units, p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units, p.barcode, p.fk_barcode_type, p.finished, p.fk_default_bom, p.mandatory_period, p.accountancy_code_buy, p.accountancy_code_buy_intra, p.accountancy_code_buy_export, p.accountancy_code_sell, p.accountancy_code_sell_intra, p.accountancy_code_sell_export, p.pmp, p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.batch_mask, p.fk_unit, p.fk_price_expression, p.price_autogen, p.model_pdf, p.stock FROM llx_product as p WHERE p.rowid = 1
2024-03-19 12:38:22 DEBUG        sql=SELECT rowid, monitor, tipo_plato FROM llx_product_extrafields WHERE fk_object = 1
2024-03-19 12:38:22 DEBUG        ProductFournisseur::find_min_price_product_fournisseur
2024-03-19 12:38:22 DEBUG        sql=SELECT s.nom as supplier_name, s.rowid as fourn_id, pfp.rowid as product_fourn_price_id, pfp.ref_fourn, pfp.price, pfp.quantity, pfp.unitprice, pfp.tva_tx, pfp.charges, pfp.remise, pfp.remise_percent, pfp.fk_supplier_price_expression, pfp.delivery_time_days ,pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code FROM llx_societe as s, llx_product_fournisseur_price as pfp WHERE s.entity IN (1) AND pfp.entity IN (1) AND pfp.fk_product = 1 AND pfp.fk_soc = s.rowid AND s.status = 1
2024-03-19 12:38:22 DEBUG        CommonObject::isExistingObject
2024-03-19 12:38:22 DEBUG        sql=SELECT rowid, ref, ref_ext FROM llx_product WHERE entity IN (1) AND rowid = 1
2024-03-19 12:38:22 DEBUG         FactureLigne::insert
2024-03-19 12:38:22 DEBUG         sql=INSERT INTO llx_facturedet (fk_facture, fk_parent_line, label, description, qty, vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, fk_product, product_type, remise_percent, subprice, ref_ext, fk_remise_except, date_start, date_end, fk_code_ventilation,  rang, special_code, fk_product_fournisseur_price, buy_price_ht, info_bits, total_ht, total_tva, total_ttc, total_localtax1, total_localtax2, situation_percent, fk_prev_id, fk_unit, fk_user_author, fk_user_modif, fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc) VALUES (906, null, null, 'Original Chicken Biscuit $340.0', 1, '', 0, 0, 0, '0', '0', 1, 0, 0, 0, '', null, '2023-11-27 04:15:23', '2023-11-27 04:15:23', 0, 0, 0, null, 0, '0', 0, 0, 0, 0, 0, 100, null, NULL, 4, 4, 0, 'TWD', 0, 0, 0, 0)
2024-03-19 12:38:22 DEBUG       Facture::update_price
2024-03-19 12:38:22 DEBUG       sql=SELECT rowid, qty, subprice as up, remise_percent, total_ht, total_tva as total_tva, total_ttc, total_localtax1 as total_localtax1, total_localtax2 as total_localtax2, tva_tx as vatrate, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, info_bits, product_type, situation_percent, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc FROM llx_facturedet WHERE fk_facture = 906 AND product_type <> 9 ORDER by rowid
2024-03-19 12:38:22 INFO         Price.lib::calcul_price_total qty=1 pu=0.00000000 remise_percent_ligne=0 txtva=0.0000 uselocaltax1_rate=0 uselocaltax2_rate=0 remise_percent_global=0 price_base_type=HT type=0 progress=100
2024-03-19 12:38:22 INFO         Price.lib::calcul_price_total MAIN_ROUNDING_RULE_TOT= pu=0.00000000 qty=1 price_base_type=HT total_ht=0-total_vat=0-total_ttc=0
2024-03-19 12:38:22 INFO         Price.lib::calcul_price_total qty=1 pu=0.00000000 remise_percent_ligne=0 txtva=0.0000 uselocaltax1_rate=0 uselocaltax2_rate=0 remise_percent_global=0 price_base_type=HT type=0 progress=100
2024-03-19 12:38:22 INFO         Price.lib::calcul_price_total MAIN_ROUNDING_RULE_TOT= pu=0.00000000 qty=1 price_base_type=HT total_ht=0-total_vat=0-total_ttc=0
2024-03-19 12:38:22 DEBUG        Facture::update_price
2024-03-19 12:38:22 DEBUG        sql=UPDATE llx_facture SET total_ht = 0, total_tva = 0, localtax1 = 0, localtax2 = 0, total_ttc = 0, multicurrency_total_ht = 0, multicurrency_total_tva = 0, multicurrency_total_ttc = 0 WHERE rowid = 906
2024-03-19 12:38:22 INFO        Trigger 'ContactRoles' for action 'BILL_CREATE' launched by /var/www/html/core/triggers/interface_90_modSociete_ContactRoles.class.php. id=906
2024-03-19 12:38:22 DEBUG       Contact::getContactRoles
2024-03-19 12:38:22 DEBUG       sql=SELECT sc.fk_socpeople as id, sc.fk_c_type_contact FROM llx_c_type_contact tc, llx_societe_contacts sc INNER JOIN llx_socpeople sp ON sc.fk_socpeople = sp.rowid AND sp.statut = 1 WHERE sc.fk_soc =14 AND sc.fk_c_type_contact=tc.rowid AND tc.element = 'facture' AND tc.active = 1
2024-03-19 12:38:22 DEBUG      COMMIT Transaction
2024-03-19 12:38:22 INFO       --- End access to /api/index.php/invoices

I noticed your post on the Dolibarr forum, where I believe you mentioned that you used curl? but will post the same both places.

First my own setup
Second my own invoice usage

Setup
I recently made my own API changes to subscriptions linking with invoices. Existing invoices though. NEW API creation of subscription can now link to existing invoice by JonBendtsen · Pull Request #28930 · Dolibarr/dolibarr · GitHub

Here’s my setup and why I mentioned the curl thing.

I use the API explorer built into Dolibarr to get, post, put, … JSON and perhaps change some parameters
http://localhost/api/index.php/explorer/

That’s the link to mine which I run inside a podman container using the v19 Tuxgasy image.

I also run a phpmyadmin container which peaks into Dolibarrs database such that I can see what is going on, as well as which tables and fields actually exist.

Next to this I have my VScodium editor where I edit the PHP files. If I make changes I can then quickly copy the files into my dolibarr container and test it out.

The first thing I do when I start my dolibarr container is to enter it, install git and then I just git init /var/www/html, and then a git commit. Because then I can always quickly revert any changes I made, and I can use git diff to see my changes inside the container, because the container image might not be 100% identical with the dolibarr git repo I have cloned to my laptop.

Own invoice usage
I don’t use invoices directly, I use the API to make a proposal, + the API to validate that proposal and then from that proposal I create an order. I have not had any issues with proposals, but what I do is to add premade products to my proposal, and then I let it calculate stuff itself. I do not set the price of the invoice.

In the file that you link to with API for the invoice, there is this line:
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';

I do not find any ref?

JonSweet16:dolibarr jonbendtsen$ grep 'public \$' htdocs/compta/facture/class/facture.class.php | grep ref
	public $ref_client;
	public $ref_customer;
	public $situation_cycle_ref;
	public $ref_ext; // External reference of the line

But I do find the total_ht and total_ttc

JonSweet16:dolibarr jonbendtsen$ grep 'public \$' htdocs/compta/facture/class/facture.class.php | grep total
	public $total_ht;
	public $total_tva;
	public $total_localtax1;
	public $total_localtax2;
	public $total_ttc;
	public $skip_update_total; // Skip update price total for special lines

When I made changes to the API to allow the subscription and invoice linking to go through, had to ensure that the objectlink was updated. NEW API creation of subscription can now link to existing invoice by JonBendtsen · Pull Request #28930 · Dolibarr/dolibarr · GitHub

Now I actually did not develop this code myself, I simply searched for code somewhere else that handled the objectlink, and then I changed the indentation. I used grep to track down the places I needed to know. I started by finding which database tables was changed by running mysqldump before and after I changed something in the GUI.

Then I noticed the database tables, I started with grep to find files that would read or write to those database tables. In my case I found this file ./htdocs/core/class/commonobject.class.php and in that file I noticed the function add_object_linked.

Next grep was to see which files used that, and among several files I looked at ./htdocs/fourn/class/fournisseur.facture-rec.class.php which contained the exact code I needed. The only changes I did was indentation when I inserted it into htdocs/adherents/class/subscription.class.php

Maybe you can use the same method to track down where ref, total_ht and total_ttc are handled. I think the total variables are auto calculated from the products and their price on the invoices.