QuickBooks Online und das Update, das Felder löscht
Eloquent sendet die geänderten Attribute. QuickBooks Online will das Objekt, das daraus werden soll. Zwischen diesen zwei Sätzen liegt ein Lieferant ohne Anschrift.
Eine QuickBooks-Online-Integration geht live. Drei Wochen später hat ein Lieferantendatensatz keine Rechnungsadresse, keine Zahlungsbedingungen und keinen Steuerschlüssel mehr, und im Protokoll steht, dass die letzte Person daran nur eine E-Mail-Adresse geändert hat.
Nichts ist kaputt. Die Integration hat genau das getan, was man ihr gesagt hat, und gesagt wurde ihr das Standardverhalten zweier Systeme, die sich darüber uneinig sind, was ein Update bedeutet.
Eloquent sendet Änderungen, die API will das Objekt
Ein save() sendet die Attribute, die dirty sind. Für eine Datenbank ist das
richtig und für diese API die falsche Nutzlast, denn sie behandelt den Body eines
Updates als den Datensatz, der daraus werden soll. Weggelassene Felder bleiben
nicht unberührt - sie werden geleert.
Die Mapping-Schicht kann also keine dünne Übersetzung der geänderten Attribute eines Models sein. Sie muss ein vollständiges Objekt erzeugen, und das heißt in der Praxis: den aktuellen Datensatz aus QuickBooks lesen, die Änderung darauf anwenden, das Ergebnis senden.
Die API unterstützt ein Teil-Update, und man sollte es nutzen. Man sollte sich aber nicht allein darauf verlassen, denn es ist ein Flag, das jemand bei genau dem einen wichtigen Aufruf vergessen kann. Vor dem Schreiben zu lesen kostet eine Anfrage und beseitigt eine Klasse stillen Datenverlusts, und in Code, der jemandes Buchhaltung ändert, ist das ein Tausch ohne Diskussionsbedarf.
Die strukturelle Folgerung: diese Integration braucht einen eigenen Mapper statt einer Methode am Model. Das Objekt, das an die Buchhaltung geht, ist nicht das Model, sondern ein daraus zusammengesetztes Dokument - und beides für dasselbe zu halten ist der Ursprung dieses Fehlers.
Die Version macht ein blindes Retry falsch
Jeder Datensatz trägt eine Version, und ein Update muss die Version mitsenden, auf der es beruht. Hat sich der Datensatz inzwischen bewegt, wird das Update abgelehnt.
Das ist gutes Verhalten und es bricht das Standard-Retry. Ein Queue-Job, der eine fertige Nutzlast hält und sie nach einem Fehlschlag erneut sendet, sendet eine Version, die schon veraltet ist - also scheitert er wieder, und wieder, bis die Versuche aufgebraucht sind, und die Änderung liegt in einer Tabelle fehlgeschlagener Jobs statt im Buchhaltungssystem.
Der Job muss daher die Absicht speichern und nicht die Nutzlast. Was er hält, ist „setze die E-Mail dieses Kunden auf diesen Wert", nicht ein serialisierter Request-Body. Bei jedem Versuch liest er den aktuellen Datensatz, wendet die Absicht an und sendet das Ergebnis mit der eben gelesenen Version.
Damit ist der Job wirklich gefahrlos zweimal ausführbar, und das zählt hier mehr als sonst, weil die Queue von Laravel wiederholt, ob es jemand eingeplant hat oder nicht.
Die zweite Hälfte der Versionsfrage ist, was bei einem echten Konflikt zu tun ist
- wenn jemand in der Buchhaltung dasselbe Feld geändert hat. Überschreiben ist eine Entscheidung, kein Standard. Für die meisten Felder lautet die ehrliche Antwort, dass das Buchhaltungssystem gewinnt und Ihre Anwendung protokolliert, dass ihre Änderung abgewiesen wurde - denn eine stille Überschreibung der Korrektur einer Buchhalterin ist das Verhalten, das die Glaubwürdigkeit einer Integration in einem Termin beendet.
Die Verbindung ist eine Firma und nicht der Nutzer
Autorisiert wird für eine bestimmte Firmendatei, und ein Login kann mehrere erteilen. Was man speichert, ist also eine Verbindung - Firmenkennung, Tokens, Zeitpunkt der letzten Erneuerung und ob sie gerade gesund ist - in einer eigenen Tabelle.
Nicht Spalten an einem Nutzer. Nicht eine Zeile in einer Settings-Tabelle. Die Firmenkennung ist der Schlüssel, denn jede weitere Anfrage erfolgt für eine Firma und die Anwendung muss wissen, für welche.
Die Token-Erneuerung hat dieselbe Gefahr wie bei jeder Buchhaltungs-API: zwei Worker erneuern im selben Moment und entwerten sich gegenseitig. Dieser Fehler und seine Behebung stehen im Xero-Text, und die Mechanik ist nah genug, dass eine Wiederholung hier Ihre Zeit verschwenden würde. Die Fristen unterscheiden sich - lesen Sie die aktuellen in der Dokumentation von Intuit nach, statt zu übernehmen, was ein Blogtext sagte - die Form des Problems nicht.
Eine QuickBooks-Besonderheit lohnt die Erwähnung: das Refresh-Token verfällt auch durch Nichtnutzung, nicht nur durch Alter. Eine Integration für einen Kunden, der Ihre Anwendung einige Monate nicht benutzt hat, kommt getrennt zurück, ohne dass etwas schiefgegangen wäre. Ein getrennter Zustand muss ein echter Zustand in Ihrem Schema sein, mit einer Erklärung in der Oberfläche, statt einer Exception, die jemanden überrascht.
Kundenabgleich ist eine Tabelle, kein Lookup
QuickBooks verlangt, dass der Anzeigename eines Kunden innerhalb einer Firma eindeutig ist. Diese eine Einschränkung verursacht den größten Teil der Schmerzen in diesen Projekten.
Ihre Datenbank hat „Acme GmbH". Deren Datenbank hat „Acme Gesellschaft mbH", außerdem „ACME GMBH - NICHT VERWENDEN" von 2019 und außerdem „Acme " mit Leerzeichen am Ende. Ein Abgleich über den Namen erzeugt beim ersten abweichenden Zusatz ein Duplikat, und Duplikate in einem Buchhaltungssystem sind Aufräumarbeit für eine Buchhalterin und kein Bug, den Sie beheben können.
Die Paarung lebt deshalb in einer Zuordnungstabelle - Ihre Kennung, deren Kennung, die zugehörige Firma - und wird durch einen einmal geprüften Abgleich gefüllt statt durch einen Zeichenkettenvergleich, der für immer läuft.
Dieser Abgleich ist keine Entwicklungsarbeit und er ist der größte Teil der Laufzeit. Er bringt außerdem die Frage hervor, die niemand gestellt hat: welches System besitzt den Namen eines Kunden, und was passiert, wenn er auf der anderen Seite geändert wird.
Entscheiden, wer die Rechnungen nummeriert
Die letzte Entscheidung ist kaufmännisch und muss vor dem ersten Commit fallen.
Vergibt QuickBooks die Rechnungsnummern, kann Ihre Anwendung keine Nummer anzeigen, bevor der Push erfolgreich war - das ändert, was ein Kunde sieht, und was passiert, wenn die Buchhaltung nicht erreichbar ist.
Vergibt Ihre Anwendung sie, muss jemand die automatische Nummerierung in QuickBooks abschalten, und Lücken in der Folge sind Ihre Sache.
Beides funktioniert. Was nicht funktioniert, ist dass beide Systeme nummerieren - das erzeugt zwei Rechnungen für einen Verkauf und eine Abstimmung, die niemand abschließen kann. Es ist ein Fünf-Minuten-Gespräch in Woche eins und zwei Wochen Entwirren im vierten Monat.
Wann man das nicht baut
Wenn Rechnungen in QuickBooks erscheinen sollen, nichts zurückkommen muss und das Volumen bei Dutzenden pro Monat liegt, ist ein fertiger Connector die richtige Antwort und er läuft heute Nachmittag.
Eine gebaute Integration verdient ihren Platz, wenn die Zuordnung spezifisch für Ihr Geschäft ist, wenn das Volumen manuelle Korrektur teuer macht, oder wenn die Buchhaltungsdaten in Ihrem eigenen System abfragbar sein müssen. Sie verdient ihn nicht als Weg, eine Gebühr zu vermeiden, denn die Kosten liegen in den Abstimmungsregeln und die sind in beiden Fällen dieselben.
