pyxero
pyxero copied to clipboard
invoice can't be saved after modification due to 'PlannedPaymentDateString'?
Trying to save a modified invoice seems to fail because of a problem with "PlannedPaymentDateString," even though that key was not changed.
to reproduce:
from xero import Xero
x = xero.invoices.get('b7bf6764-85c5-4528-965f-fe02c5d3b9ad') this is a known open AP ID and all fields and values print as expected
x[0]['Reference'] = 'test' the change to Reference is visible when printed
xero.invoices.save(x) Traceback (most recent call last): File "", line 1, in
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/xero/basemanager.py", line 202, in wrapper raise XeroBadRequest(response) xero.exceptions.XeroBadRequest: PostDataInvalidException: The element 'PlannedPaymentDateString' was not recognised. Ensure the element name has the correct case and that there are no duplicate elements of the same name.
It looks like Xero are now returning PlannedPaymentDateString (although this doesn't appear to be documented anywhere) and it's a read only field, so when you try to save the invoice PyXero sends the field back to Xero, and they return the error you're seeing.
PlannedPaymentDateString needs to be added to xero/basemanager.py NO_SEND_FIELDS tuple to stop it being sent back to Xero.
Yes, poking around some ore late this morning, I found that removing the PlannedPaymentDateString k/v pair before the save worked around the problem. On this page Xero does mention the string keys:
"For some elements we also include a date string value on JSON responses to help with reading date values. e.g. DateString, DueDateString."
... but as you say, this is not documented in the Invoices object documentation proper.
FWIW, we had a similar issue just recently, getting the unhelpful error:
XeroBadRequest: PostDataInvalidException: Object reference not set to an instance of an object.
Couldn't pin down exactly which field(s) caused the explosion, but a legitimate solution (IMO) is just to strip out the Contact data before sending the Invoice back. Idk why it's even there...
xero_invoice = xero.invoices.get(guid)[0]
for k, v in data.items():
xero_invoice[k] = v
xero_invoice['Contact'] = {'ContactID': xero_invoice['Contact']['ContactID']}
xero.invoices.save(xero_invoice)