Просмотр исходного кода

Offer TAX and NON to US QuickBooks companies, make the start date a date picker, and say what Sync now does (#329)

Bernt Christian Egeland 3 недель назад
Родитель
Сommit
d0f882d33e

+ 7 - 3
messages/de/integrations.json

@@ -96,10 +96,14 @@
     "testPassed": "Verbindung funktioniert",
     "syncNow": "Jetzt synchronisieren",
     "syncQueued": "Synchronisierung eingereiht; sie läuft innerhalb einer Minute",
+    "pullNow": "Zahlungen jetzt abrufen",
+    "pullQueued": "Zahlungsabruf eingereiht; er läuft innerhalb einer Minute",
     "backfill": "Geplante Aufträge übertragen",
     "backfillQueued": "Die geplanten Aufträge ab der letzten Woche wurden eingereiht",
     "backfillInvoices": "Ausgestellte Rechnungen übertragen",
     "backfillInvoicesQueued": "Die in den letzten 90 Tagen ausgestellten Rechnungen wurden eingereiht",
+    "backfillInvoicesQueuedCount": "{count, plural, one {# Rechnung} other {# Rechnungen}} aus den letzten 90 Tagen eingereiht",
+    "backfillInvoicesNone": "Keine in den letzten 90 Tagen ausgestellten Rechnungen zum Übertragen. Nur gesendete, geteilte oder bezahlte Rechnungen werden übertragen.",
     "retryQueued": "Job erneut eingereiht",
     "settingsTitle": "Einstellungen",
     "settingsDescription": "Was synchronisiert wird und wohin. Änderungen gelten ab der nächsten Synchronisierung.",
@@ -496,7 +500,7 @@
         "pushOnComplete": "Rechnungen auch senden, wenn der Auftrag als abgeschlossen markiert wird",
         "pushOnCompleteHelp": "Ohne diese Option geht eine Rechnung erst über, wenn sie gesendet, geteilt oder bezahlt wurde. Mit ihr geht ein abgeschlossener Auftrag sofort über und wird bei Änderungen aktualisiert.",
         "startDate": "Nur Rechnungen mit Datum ab",
-        "startDateHelp": "JJJJ-MM-TT. Leer lassen, um jede ausgestellte Rechnung zu senden. Nutze das Datum, an dem deine Bücher zu QuickBooks gewechselt sind, damit ältere Rechnungen nicht doppelt erfasst werden.",
+        "startDateHelp": "Leer lassen, um jede ausgestellte Rechnung zu senden. Nutze das Datum, an dem deine Bücher zu QuickBooks gewechselt sind, damit ältere Rechnungen nicht doppelt erfasst werden.",
         "includeVehicle": "Fahrzeug auf der Rechnung nennen",
         "includeVehicleHelp": "Eine Textzeile über den Positionen mit Baujahr, Marke, Modell, Kennzeichen und Kilometerstand, damit die Buchhaltung weiß, um welches Auto es geht.",
         "laborItemId": "Artikel für Arbeitspositionen",
@@ -504,9 +508,9 @@
         "partsItemId": "Artikel für Teilepositionen",
         "partsItemIdHelp": "Leer lassen, dann wird beim ersten Mal ein Artikel namens Parts unter deinem Ertragskonto angelegt.",
         "taxCodeId": "Steuercode für steuerpflichtige Rechnungen",
-        "taxCodeIdHelp": "QuickBooks berechnet die Steuer aus diesem Code. Wähle den, dessen Satz dem Steuersatz deiner Rechnungen entspricht. In einer US-Firma TAX wählen.",
+        "taxCodeIdHelp": "QuickBooks berechnet die Steuer aus diesem Code. Wähle den, dessen Satz dem Steuersatz deiner Rechnungen entspricht. Ein US-Unternehmen verwendet TAX, sofern du nichts anderes wählst.",
         "zeroTaxCodeId": "Steuercode für steuerfreie Rechnungen",
-        "zeroTaxCodeIdHelp": "Wird verwendet, wenn die Rechnung keine Steuer hat oder der Kunde steuerbefreit ist. In einer US-Firma NON wählen.",
+        "zeroTaxCodeIdHelp": "Wird verwendet, wenn die Rechnung keine Steuer hat oder der Kunde steuerbefreit ist. Ein US-Unternehmen verwendet NON, sofern du nichts anderes wählst.",
         "pushPayments": "Zahlungen in QuickBooks erfassen",
         "depositAccountId": "Zahlungen einzahlen auf",
         "depositAccountIdHelp": "Leer lassen, um Undeposited Funds zu verwenden.",

+ 7 - 3
messages/en/integrations.json

@@ -96,10 +96,14 @@
     "testPassed": "Connection works",
     "syncNow": "Sync now",
     "syncQueued": "Sync queued; it runs within a minute",
+    "pullNow": "Pull payments now",
+    "pullQueued": "Payment pull queued; it runs within a minute",
     "backfill": "Push scheduled work orders",
     "backfillQueued": "Queued the scheduled work orders from the last week onwards",
     "backfillInvoices": "Push issued invoices",
     "backfillInvoicesQueued": "Queued the invoices issued in the last 90 days",
+    "backfillInvoicesQueuedCount": "Queued {count, plural, one {# invoice} other {# invoices}} issued in the last 90 days",
+    "backfillInvoicesNone": "No invoices issued in the last 90 days to push. Only sent, shared or paid invoices go over.",
     "retryQueued": "Job queued again",
     "settingsTitle": "Settings",
     "settingsDescription": "What to sync and where. Changes apply to the next sync.",
@@ -496,7 +500,7 @@
         "pushOnComplete": "Also send invoices when the job is marked completed",
         "pushOnCompleteHelp": "Without this an invoice goes over once it is sent, shared or paid. With it, a completed job goes over straight away and is updated if it changes.",
         "startDate": "Only invoices dated on or after",
-        "startDateHelp": "YYYY-MM-DD. Leave empty to send every issued invoice. Use the date your books moved to QuickBooks so older invoices are not entered twice.",
+        "startDateHelp": "Leave empty to send every issued invoice. Use the date your books moved to QuickBooks so older invoices are not entered twice.",
         "includeVehicle": "Name the vehicle on the invoice",
         "includeVehicleHelp": "A text line above the charges with the year, make, model, plate and mileage, so the books say which car.",
         "laborItemId": "Item for labour lines",
@@ -504,9 +508,9 @@
         "partsItemId": "Item for parts lines",
         "partsItemIdHelp": "Leave empty and an item named Parts is created under your income account the first time.",
         "taxCodeId": "Tax code for taxable invoices",
-        "taxCodeIdHelp": "QuickBooks works the tax out from this code, so pick the one whose rate matches the tax rate on your invoices. In a US company choose TAX.",
+        "taxCodeIdHelp": "QuickBooks works the tax out from this code, so pick the one whose rate matches the tax rate on your invoices. A US company uses TAX unless you choose otherwise.",
         "zeroTaxCodeId": "Tax code for tax-free invoices",
-        "zeroTaxCodeIdHelp": "Used when the invoice has no tax or the customer is tax exempt. In a US company choose NON.",
+        "zeroTaxCodeIdHelp": "Used when the invoice has no tax or the customer is tax exempt. A US company uses NON unless you choose otherwise.",
         "pushPayments": "Record payments in QuickBooks",
         "depositAccountId": "Deposit payments to",
         "depositAccountIdHelp": "Leave empty to use Undeposited Funds.",

+ 7 - 3
messages/es/integrations.json

@@ -96,10 +96,14 @@
     "testPassed": "La conexión funciona",
     "syncNow": "Sincronizar ahora",
     "syncQueued": "Sincronización en cola; se ejecuta en menos de un minuto",
+    "pullNow": "Traer pagos ahora",
+    "pullQueued": "Lectura de pagos en cola; se ejecuta en menos de un minuto",
     "backfill": "Enviar órdenes de trabajo programadas",
     "backfillQueued": "Se pusieron en cola las órdenes de trabajo programadas desde la semana pasada en adelante",
     "backfillInvoices": "Enviar facturas emitidas",
     "backfillInvoicesQueued": "Se pusieron en cola las facturas emitidas en los últimos 90 días",
+    "backfillInvoicesQueuedCount": "{count, plural, one {# factura emitida} other {# facturas emitidas}} en los últimos 90 días en cola",
+    "backfillInvoicesNone": "No hay facturas emitidas en los últimos 90 días para enviar. Solo pasan las facturas enviadas, compartidas o pagadas.",
     "retryQueued": "Tarea puesta en cola de nuevo",
     "settingsTitle": "Configuración",
     "settingsDescription": "Qué sincronizar y dónde. Los cambios se aplican en la próxima sincronización.",
@@ -496,7 +500,7 @@
         "pushOnComplete": "Enviar también las facturas cuando el trabajo se marque como completado",
         "pushOnCompleteHelp": "Sin esto, una factura pasa cuando se envía, se comparte o se paga. Con esto, un trabajo completado pasa de inmediato y se actualiza si cambia.",
         "startDate": "Solo facturas con fecha igual o posterior a",
-        "startDateHelp": "AAAA-MM-DD. Déjalo vacío para enviar todas las facturas emitidas. Usa la fecha en que tu contabilidad pasó a QuickBooks para no registrar dos veces las facturas antiguas.",
+        "startDateHelp": "Déjalo vacío para enviar todas las facturas emitidas. Usa la fecha en que tu contabilidad pasó a QuickBooks para no registrar dos veces las facturas antiguas.",
         "includeVehicle": "Indicar el vehículo en la factura",
         "includeVehicleHelp": "Una línea de texto encima de los cargos con año, marca, modelo, matrícula y kilometraje, para que la contabilidad sepa de qué coche se trata.",
         "laborItemId": "Artículo para líneas de mano de obra",
@@ -504,9 +508,9 @@
         "partsItemId": "Artículo para líneas de piezas",
         "partsItemIdHelp": "Déjalo vacío y la primera vez se creará un artículo llamado Parts en tu cuenta de ingresos.",
         "taxCodeId": "Código de impuesto para facturas gravadas",
-        "taxCodeIdHelp": "QuickBooks calcula el impuesto a partir de este código, así que elige el que tenga el mismo tipo que tus facturas. En una empresa de EE. UU. elige TAX.",
+        "taxCodeIdHelp": "QuickBooks calcula el impuesto a partir de este código, así que elige el que tenga la misma tasa que el impuesto de tus facturas. Una empresa de EE. UU. usa TAX salvo que elijas otro código.",
         "zeroTaxCodeId": "Código de impuesto para facturas sin impuesto",
-        "zeroTaxCodeIdHelp": "Se usa cuando la factura no tiene impuesto o el cliente está exento. En una empresa de EE. UU. elige NON.",
+        "zeroTaxCodeIdHelp": "Se usa cuando la factura no lleva impuesto o el cliente está exento. Una empresa de EE. UU. usa NON salvo que elijas otro código.",
         "pushPayments": "Registrar pagos en QuickBooks",
         "depositAccountId": "Depositar pagos en",
         "depositAccountIdHelp": "Déjalo vacío para usar Undeposited Funds.",

+ 7 - 3
messages/fr/integrations.json

@@ -96,10 +96,14 @@
     "testPassed": "La connexion fonctionne",
     "syncNow": "Synchroniser maintenant",
     "syncQueued": "Synchronisation en file d'attente ; elle démarre d'ici une minute",
+    "pullNow": "Récupérer les paiements maintenant",
+    "pullQueued": "Récupération des paiements en file d'attente ; elle démarre d'ici une minute",
     "backfill": "Envoyer les ordres de travail planifiés",
     "backfillQueued": "Les ordres de travail planifiés depuis la semaine dernière ont été mis en file d'attente",
     "backfillInvoices": "Envoyer les factures émises",
     "backfillInvoicesQueued": "Les factures émises ces 90 derniers jours ont été mises en file",
+    "backfillInvoicesQueuedCount": "Mise en file de {count, plural, one {# facture émise} other {# factures émises}} ces 90 derniers jours",
+    "backfillInvoicesNone": "Aucune facture émise ces 90 derniers jours à envoyer. Seules les factures envoyées, partagées ou payées sont transmises.",
     "retryQueued": "Tâche remise en file d'attente",
     "settingsTitle": "Paramètres",
     "settingsDescription": "Ce qu'il faut synchroniser et vers où. Les modifications s'appliquent à la prochaine synchronisation.",
@@ -496,7 +500,7 @@
         "pushOnComplete": "Envoyer aussi les factures quand le travail est marqué terminé",
         "pushOnCompleteHelp": "Sans cette option, une facture part une fois envoyée, partagée ou payée. Avec, un travail terminé part tout de suite et est mis à jour s'il change.",
         "startDate": "Uniquement les factures datées à partir du",
-        "startDateHelp": "AAAA-MM-JJ. Laissez vide pour envoyer toutes les factures émises. Utilisez la date où votre comptabilité est passée sur QuickBooks pour ne pas saisir deux fois les anciennes factures.",
+        "startDateHelp": "Laissez vide pour envoyer toutes les factures émises. Utilisez la date où votre comptabilité est passée sur QuickBooks pour ne pas saisir deux fois les anciennes factures.",
         "includeVehicle": "Indiquer le véhicule sur la facture",
         "includeVehicleHelp": "Une ligne de texte au-dessus des lignes facturées avec l'année, la marque, le modèle, la plaque et le kilométrage, pour que la comptabilité sache de quelle voiture il s'agit.",
         "laborItemId": "Article pour les lignes de main-d'œuvre",
@@ -504,9 +508,9 @@
         "partsItemId": "Article pour les lignes de pièces",
         "partsItemIdHelp": "Laissez vide et un article nommé Parts sera créé sous votre compte de produits la première fois.",
         "taxCodeId": "Code de taxe pour les factures taxables",
-        "taxCodeIdHelp": "QuickBooks calcule la taxe à partir de ce code : choisissez celui dont le taux correspond à celui de vos factures. Dans une entreprise américaine, choisissez TAX.",
+        "taxCodeIdHelp": "QuickBooks calcule la taxe à partir de ce code : choisissez celui dont le taux correspond à celui de vos factures. Une société américaine utilise TAX sauf si vous choisissez un autre code.",
         "zeroTaxCodeId": "Code de taxe pour les factures sans taxe",
-        "zeroTaxCodeIdHelp": "Utilisé quand la facture n'a pas de taxe ou que le client est exonéré. Dans une entreprise américaine, choisissez NON.",
+        "zeroTaxCodeIdHelp": "Utilisé quand la facture n'a pas de taxe ou que le client est exonéré. Une société américaine utilise NON sauf si vous choisissez un autre code.",
         "pushPayments": "Enregistrer les paiements dans QuickBooks",
         "depositAccountId": "Déposer les paiements sur",
         "depositAccountIdHelp": "Laissez vide pour utiliser Undeposited Funds.",

+ 7 - 3
messages/it/integrations.json

@@ -96,10 +96,14 @@
     "testPassed": "La connessione funziona",
     "syncNow": "Sincronizza ora",
     "syncQueued": "Sincronizzazione in coda; verrà eseguita entro un minuto",
+    "pullNow": "Recupera i pagamenti ora",
+    "pullQueued": "Recupero pagamenti in coda; verrà eseguito entro un minuto",
     "backfill": "Invia gli ordini di lavoro pianificati",
     "backfillQueued": "Messi in coda gli ordini di lavoro pianificati dall'ultima settimana in poi",
     "backfillInvoices": "Invia le fatture emesse",
     "backfillInvoicesQueued": "Le fatture emesse negli ultimi 90 giorni sono in coda",
+    "backfillInvoicesQueuedCount": "In coda {count, plural, one {# fattura emessa} other {# fatture emesse}} negli ultimi 90 giorni",
+    "backfillInvoicesNone": "Nessuna fattura emessa negli ultimi 90 giorni da inviare. Passano solo le fatture inviate, condivise o pagate.",
     "retryQueued": "Attività rimessa in coda",
     "settingsTitle": "Impostazioni",
     "settingsDescription": "Cosa sincronizzare e dove. Le modifiche si applicano alla prossima sincronizzazione.",
@@ -496,7 +500,7 @@
         "pushOnComplete": "Invia le fatture anche quando il lavoro viene segnato come completato",
         "pushOnCompleteHelp": "Senza questa opzione una fattura passa quando viene inviata, condivisa o pagata. Con questa, un lavoro completato passa subito e viene aggiornato se cambia.",
         "startDate": "Solo fatture con data a partire dal",
-        "startDateHelp": "AAAA-MM-GG. Lascia vuoto per inviare ogni fattura emessa. Usa la data in cui la contabilità è passata a QuickBooks, così le fatture più vecchie non vengono registrate due volte.",
+        "startDateHelp": "Lascia vuoto per inviare ogni fattura emessa. Usa la data in cui la contabilità è passata a QuickBooks, così le fatture più vecchie non vengono registrate due volte.",
         "includeVehicle": "Indicare il veicolo sulla fattura",
         "includeVehicleHelp": "Una riga di testo sopra le voci con anno, marca, modello, targa e chilometraggio, così la contabilità sa di quale auto si tratta.",
         "laborItemId": "Articolo per le righe di manodopera",
@@ -504,9 +508,9 @@
         "partsItemId": "Articolo per le righe di ricambi",
         "partsItemIdHelp": "Lascia vuoto e la prima volta verrà creato un articolo chiamato Parts sotto il tuo conto ricavi.",
         "taxCodeId": "Codice imposta per le fatture imponibili",
-        "taxCodeIdHelp": "QuickBooks calcola l'imposta da questo codice: scegli quello con la stessa aliquota delle tue fatture. In un'azienda USA scegli TAX.",
+        "taxCodeIdHelp": "QuickBooks calcola l'imposta da questo codice: scegli quello con la stessa aliquota delle tue fatture. Un'azienda statunitense usa TAX se non scegli un altro codice.",
         "zeroTaxCodeId": "Codice imposta per le fatture senza imposta",
-        "zeroTaxCodeIdHelp": "Usato quando la fattura non ha imposta o il cliente è esente. In un'azienda USA scegli NON.",
+        "zeroTaxCodeIdHelp": "Usato quando la fattura non ha imposta o il cliente è esente. Un'azienda statunitense usa NON se non scegli un altro codice.",
         "pushPayments": "Registra i pagamenti in QuickBooks",
         "depositAccountId": "Deposita i pagamenti su",
         "depositAccountIdHelp": "Lascia vuoto per usare Undeposited Funds.",

+ 7 - 3
messages/lt/integrations.json

@@ -96,10 +96,14 @@
     "testPassed": "Ryšys veikia",
     "syncNow": "Sinchronizuoti dabar",
     "syncQueued": "Sinchronizavimas eilėje; jis įvyks per minutę",
+    "pullNow": "Gauti mokėjimus dabar",
+    "pullQueued": "Mokėjimų nuskaitymas eilėje; jis įvyks per minutę",
     "backfill": "Perkelti suplanuotus darbo užsakymus",
     "backfillQueued": "Į eilę įtraukti suplanuoti darbo užsakymai nuo praėjusios savaitės",
     "backfillInvoices": "Siųsti išrašytas sąskaitas",
     "backfillInvoicesQueued": "Per pastarąsias 90 dienų išrašytos sąskaitos įtrauktos į eilę",
+    "backfillInvoicesQueuedCount": "Į eilę įtraukta {count, plural, one {# sąskaita, išrašyta} few {# sąskaitos, išrašytos} other {# sąskaitų, išrašytų}} per pastarąsias 90 dienų",
+    "backfillInvoicesNone": "Per pastarąsias 90 dienų išrašytų sąskaitų siųsti nėra. Perduodamos tik išsiųstos, pasidalintos ar apmokėtos sąskaitos.",
     "retryQueued": "Užduotis vėl įtraukta į eilę",
     "settingsTitle": "Nustatymai",
     "settingsDescription": "Ką sinchronizuoti ir kur. Pakeitimai įsigalios kito sinchronizavimo metu.",
@@ -496,7 +500,7 @@
         "pushOnComplete": "Siųsti sąskaitas ir tada, kai darbas pažymimas kaip užbaigtas",
         "pushOnCompleteHelp": "Be šio nustatymo sąskaita perduodama, kai ji išsiunčiama, pasidalinama ar apmokama. Su juo užbaigtas darbas perduodamas iš karto ir atnaujinamas, jei pasikeičia.",
         "startDate": "Tik sąskaitos, datuotos nuo",
-        "startDateHelp": "MMMM-MM-DD. Palikite tuščią, kad būtų siunčiamos visos išrašytos sąskaitos. Naudokite datą, kada apskaita perkelta į QuickBooks, kad senesnės sąskaitos nebūtų įvestos dukart.",
+        "startDateHelp": "Palikite tuščią, kad būtų siunčiamos visos išrašytos sąskaitos. Naudokite datą, kada apskaita perkelta į QuickBooks, kad senesnės sąskaitos nebūtų įvestos dukart.",
         "includeVehicle": "Nurodyti transporto priemonę sąskaitoje",
         "includeVehicleHelp": "Teksto eilutė virš pozicijų su metais, marke, modeliu, numeriu ir rida, kad apskaita žinotų, apie kurį automobilį kalbama.",
         "laborItemId": "Prekė darbo eilutėms",
@@ -504,9 +508,9 @@
         "partsItemId": "Prekė dalių eilutėms",
         "partsItemIdHelp": "Palikite tuščią ir pirmą kartą po jūsų pajamų sąskaita bus sukurta prekė pavadinimu Parts.",
         "taxCodeId": "Mokesčio kodas apmokestinamoms sąskaitoms",
-        "taxCodeIdHelp": "QuickBooks apskaičiuoja mokestį pagal šį kodą, todėl pasirinkite tą, kurio tarifas sutampa su jūsų sąskaitų mokesčio tarifu. JAV įmonėje pasirinkite TAX.",
+        "taxCodeIdHelp": "QuickBooks apskaičiuoja mokestį pagal šį kodą, todėl pasirinkite tą, kurio tarifas sutampa su jūsų sąskaitų mokesčio tarifu. JAV įmonė naudoja TAX, nebent pasirinksite kitą kodą.",
         "zeroTaxCodeId": "Mokesčio kodas sąskaitoms be mokesčio",
-        "zeroTaxCodeIdHelp": "Naudojamas, kai sąskaitoje nėra mokesčio arba klientas atleistas nuo mokesčio. JAV įmonėje pasirinkite NON.",
+        "zeroTaxCodeIdHelp": "Naudojamas, kai sąskaitoje nėra mokesčio arba klientas atleistas nuo mokesčio. JAV įmonė naudoja NON, nebent pasirinksite kitą kodą.",
         "pushPayments": "Registruoti mokėjimus QuickBooks",
         "depositAccountId": "Mokėjimus įnešti į",
         "depositAccountIdHelp": "Palikite tuščią, kad būtų naudojama Undeposited Funds.",

+ 7 - 3
messages/nb/integrations.json

@@ -96,10 +96,14 @@
     "testPassed": "Tilkoblingen fungerer",
     "syncNow": "Synkroniser nå",
     "syncQueued": "Synkronisering lagt i kø; den kjører innen ett minutt",
+    "pullNow": "Hent betalinger nå",
+    "pullQueued": "Henting av betalinger lagt i kø; den kjører innen ett minutt",
     "backfill": "Send planlagte arbeidsordre",
     "backfillQueued": "La planlagte arbeidsordre fra og med forrige uke i kø",
     "backfillInvoices": "Send utstedte fakturaer",
     "backfillInvoicesQueued": "Fakturaene utstedt de siste 90 dagene er lagt i kø",
+    "backfillInvoicesQueuedCount": "{count, plural, one {# faktura} other {# fakturaer}} utstedt de siste 90 dagene lagt i kø",
+    "backfillInvoicesNone": "Ingen fakturaer utstedt de siste 90 dagene å sende. Bare sendte, delte eller betalte fakturaer går over.",
     "retryQueued": "Jobben er lagt i kø på nytt",
     "settingsTitle": "Innstillinger",
     "settingsDescription": "Hva som skal synkroniseres og hvor. Endringer gjelder fra neste synkronisering.",
@@ -496,7 +500,7 @@
         "pushOnComplete": "Send også fakturaer når jobben markeres som fullført",
         "pushOnCompleteHelp": "Uten dette går en faktura over når den er sendt, delt eller betalt. Med det går en fullført jobb over med en gang og oppdateres om den endres.",
         "startDate": "Bare fakturaer datert fra og med",
-        "startDateHelp": "ÅÅÅÅ-MM-DD. La stå tomt for å sende alle utstedte fakturaer. Bruk datoen regnskapet flyttet til QuickBooks, så eldre fakturaer ikke føres to ganger.",
+        "startDateHelp": "La stå tomt for å sende alle utstedte fakturaer. Bruk datoen regnskapet flyttet til QuickBooks, så eldre fakturaer ikke føres to ganger.",
         "includeVehicle": "Oppgi kjøretøyet på fakturaen",
         "includeVehicleHelp": "En tekstlinje over postene med årsmodell, merke, modell, skilt og kilometerstand, så regnskapet vet hvilken bil det gjelder.",
         "laborItemId": "Vare for arbeidslinjer",
@@ -504,9 +508,9 @@
         "partsItemId": "Vare for delelinjer",
         "partsItemIdHelp": "La stå tomt, så opprettes en vare kalt Parts under inntektskontoen din første gang.",
         "taxCodeId": "Avgiftskode for avgiftspliktige fakturaer",
-        "taxCodeIdHelp": "QuickBooks regner ut avgiften fra denne koden, så velg den med samme sats som mva-satsen på fakturaene dine. I et amerikansk selskap velger du TAX.",
+        "taxCodeIdHelp": "QuickBooks regner ut avgiften fra denne koden, så velg den med samme sats som mva-satsen på fakturaene dine. Et amerikansk selskap bruker TAX med mindre du velger noe annet.",
         "zeroTaxCodeId": "Avgiftskode for avgiftsfrie fakturaer",
-        "zeroTaxCodeIdHelp": "Brukes når fakturaen er uten avgift eller kunden er fritatt. I et amerikansk selskap velger du NON.",
+        "zeroTaxCodeIdHelp": "Brukes når fakturaen er uten avgift eller kunden er fritatt. Et amerikansk selskap bruker NON med mindre du velger noe annet.",
         "pushPayments": "Registrer betalinger i QuickBooks",
         "depositAccountId": "Sett betalinger inn på",
         "depositAccountIdHelp": "La stå tomt for å bruke Undeposited Funds.",

+ 7 - 3
messages/nl/integrations.json

@@ -96,10 +96,14 @@
     "testPassed": "Verbinding werkt",
     "syncNow": "Nu synchroniseren",
     "syncQueued": "Synchronisatie in wachtrij; wordt binnen een minuut uitgevoerd",
+    "pullNow": "Betalingen nu ophalen",
+    "pullQueued": "Ophalen van betalingen in wachtrij; wordt binnen een minuut uitgevoerd",
     "backfill": "Geplande werkorders doorsturen",
     "backfillQueued": "Geplande werkorders vanaf afgelopen week in de wachtrij gezet",
     "backfillInvoices": "Uitgegeven facturen versturen",
     "backfillInvoicesQueued": "De facturen van de afgelopen 90 dagen staan in de wachtrij",
+    "backfillInvoicesQueuedCount": "{count, plural, one {# factuur} other {# facturen}} van de afgelopen 90 dagen in de wachtrij gezet",
+    "backfillInvoicesNone": "Geen facturen van de afgelopen 90 dagen om te sturen. Alleen verzonden, gedeelde of betaalde facturen gaan over.",
     "retryQueued": "Taak opnieuw in de wachtrij gezet",
     "settingsTitle": "Instellingen",
     "settingsDescription": "Wat er wordt gesynchroniseerd en waarheen. Wijzigingen gelden vanaf de volgende synchronisatie.",
@@ -496,7 +500,7 @@
         "pushOnComplete": "Facturen ook sturen zodra de klus als voltooid is gemarkeerd",
         "pushOnCompleteHelp": "Zonder deze optie gaat een factuur over zodra hij is verzonden, gedeeld of betaald. Met deze optie gaat een voltooide klus direct over en wordt hij bijgewerkt als er iets verandert.",
         "startDate": "Alleen facturen gedateerd op of na",
-        "startDateHelp": "JJJJ-MM-DD. Laat leeg om elke uitgegeven factuur te sturen. Gebruik de datum waarop je boekhouding naar QuickBooks is overgegaan, zodat oudere facturen niet dubbel worden ingevoerd.",
+        "startDateHelp": "Laat leeg om elke uitgegeven factuur te sturen. Gebruik de datum waarop je boekhouding naar QuickBooks is overgegaan, zodat oudere facturen niet dubbel worden ingevoerd.",
         "includeVehicle": "Het voertuig op de factuur vermelden",
         "includeVehicleHelp": "Een tekstregel boven de posten met bouwjaar, merk, model, kenteken en kilometerstand, zodat de boekhouding weet om welke auto het gaat.",
         "laborItemId": "Artikel voor arbeidsregels",
@@ -504,9 +508,9 @@
         "partsItemId": "Artikel voor onderdelenregels",
         "partsItemIdHelp": "Laat leeg en de eerste keer wordt een artikel met de naam Parts aangemaakt onder je opbrengstenrekening.",
         "taxCodeId": "Btw-code voor belaste facturen",
-        "taxCodeIdHelp": "QuickBooks berekent de belasting uit deze code, kies dus de code met hetzelfde tarief als op je facturen. In een Amerikaans bedrijf kies je TAX.",
+        "taxCodeIdHelp": "QuickBooks berekent de belasting uit deze code, kies dus de code met hetzelfde tarief als op je facturen. Een Amerikaans bedrijf gebruikt TAX tenzij je iets anders kiest.",
         "zeroTaxCodeId": "Btw-code voor facturen zonder belasting",
-        "zeroTaxCodeIdHelp": "Gebruikt als de factuur geen belasting heeft of de klant is vrijgesteld. In een Amerikaans bedrijf kies je NON.",
+        "zeroTaxCodeIdHelp": "Gebruikt als de factuur geen belasting heeft of de klant is vrijgesteld. Een Amerikaans bedrijf gebruikt NON tenzij je iets anders kiest.",
         "pushPayments": "Betalingen in QuickBooks registreren",
         "depositAccountId": "Betalingen storten op",
         "depositAccountIdHelp": "Laat leeg om Undeposited Funds te gebruiken.",

+ 7 - 3
messages/pl/integrations.json

@@ -96,10 +96,14 @@
     "testPassed": "Połączenie działa",
     "syncNow": "Synchronizuj teraz",
     "syncQueued": "Synchronizacja w kolejce; uruchomi się w ciągu minuty",
+    "pullNow": "Pobierz płatności teraz",
+    "pullQueued": "Pobieranie płatności w kolejce; uruchomi się w ciągu minuty",
     "backfill": "Wyślij zaplanowane zlecenia",
     "backfillQueued": "Dodano do kolejki zaplanowane zlecenia od ubiegłego tygodnia wzwyż",
     "backfillInvoices": "Wyślij wystawione faktury",
     "backfillInvoicesQueued": "Faktury wystawione w ciągu ostatnich 90 dni trafiły do kolejki",
+    "backfillInvoicesQueuedCount": "Do kolejki trafiło {count, plural, one {# faktura wystawiona} few {# faktury wystawione} many {# faktur wystawionych} other {# faktury wystawionej}} w ciągu ostatnich 90 dni",
+    "backfillInvoicesNone": "Brak faktur wystawionych w ciągu ostatnich 90 dni do wysłania. Przechodzą tylko faktury wysłane, udostępnione lub opłacone.",
     "retryQueued": "Zadanie ponownie w kolejce",
     "settingsTitle": "Ustawienia",
     "settingsDescription": "Co synchronizować i dokąd. Zmiany obowiązują od następnej synchronizacji.",
@@ -496,7 +500,7 @@
         "pushOnComplete": "Wysyłaj faktury także wtedy, gdy zlecenie zostanie oznaczone jako ukończone",
         "pushOnCompleteHelp": "Bez tej opcji faktura trafia do księgowości po wysłaniu, udostępnieniu lub opłaceniu. Z nią ukończone zlecenie trafia od razu i jest aktualizowane, gdy się zmieni.",
         "startDate": "Tylko faktury z datą od",
-        "startDateHelp": "RRRR-MM-DD. Zostaw puste, aby wysyłać każdą wystawioną fakturę. Użyj daty przeniesienia księgowości do QuickBooks, aby starsze faktury nie zostały wprowadzone dwa razy.",
+        "startDateHelp": "Zostaw puste, aby wysyłać każdą wystawioną fakturę. Użyj daty przeniesienia księgowości do QuickBooks, aby starsze faktury nie zostały wprowadzone dwa razy.",
         "includeVehicle": "Podaj pojazd na fakturze",
         "includeVehicleHelp": "Wiersz tekstu nad pozycjami z rocznikiem, marką, modelem, rejestracją i przebiegiem, aby księgowość wiedziała, o który samochód chodzi.",
         "laborItemId": "Pozycja dla robocizny",
@@ -504,9 +508,9 @@
         "partsItemId": "Pozycja dla części",
         "partsItemIdHelp": "Zostaw puste, a za pierwszym razem na Twoim koncie przychodów zostanie utworzona pozycja o nazwie Parts.",
         "taxCodeId": "Kod podatku dla faktur opodatkowanych",
-        "taxCodeIdHelp": "QuickBooks wylicza podatek z tego kodu, więc wybierz ten, którego stawka odpowiada stawce na Twoich fakturach. W firmie z USA wybierz TAX.",
+        "taxCodeIdHelp": "QuickBooks wylicza podatek z tego kodu, więc wybierz ten, którego stawka odpowiada stawce na Twoich fakturach. Firma z USA używa TAX, chyba że wybierzesz inny kod.",
         "zeroTaxCodeId": "Kod podatku dla faktur bez podatku",
-        "zeroTaxCodeIdHelp": "Używany, gdy faktura nie ma podatku lub klient jest zwolniony. W firmie z USA wybierz NON.",
+        "zeroTaxCodeIdHelp": "Używany, gdy faktura nie ma podatku lub klient jest zwolniony. Firma z USA używa NON, chyba że wybierzesz inny kod.",
         "pushPayments": "Rejestruj płatności w QuickBooks",
         "depositAccountId": "Wpłacaj płatności na",
         "depositAccountIdHelp": "Zostaw puste, aby użyć Undeposited Funds.",

+ 7 - 3
messages/pt-BR/integrations.json

@@ -96,10 +96,14 @@
     "testPassed": "A conexão funciona",
     "syncNow": "Sincronizar agora",
     "syncQueued": "Sincronização na fila; será executada em até um minuto",
+    "pullNow": "Buscar pagamentos agora",
+    "pullQueued": "Busca de pagamentos na fila; será executada em até um minuto",
     "backfill": "Enviar ordens de serviço agendadas",
     "backfillQueued": "Ordens de serviço agendadas a partir da semana passada colocadas na fila",
     "backfillInvoices": "Enviar faturas emitidas",
     "backfillInvoicesQueued": "As faturas emitidas nos últimos 90 dias entraram na fila",
+    "backfillInvoicesQueuedCount": "{count, plural, one {# fatura emitida} other {# faturas emitidas}} nos últimos 90 dias na fila",
+    "backfillInvoicesNone": "Nenhuma fatura emitida nos últimos 90 dias para enviar. Só passam faturas enviadas, compartilhadas ou pagas.",
     "retryQueued": "Tarefa colocada na fila novamente",
     "settingsTitle": "Configurações",
     "settingsDescription": "O que sincronizar e para onde. As alterações valem a partir da próxima sincronização.",
@@ -496,7 +500,7 @@
         "pushOnComplete": "Enviar faturas também quando o serviço for marcado como concluído",
         "pushOnCompleteHelp": "Sem isso, uma fatura vai quando é enviada, compartilhada ou paga. Com isso, um serviço concluído vai na hora e é atualizado se mudar.",
         "startDate": "Somente faturas com data a partir de",
-        "startDateHelp": "AAAA-MM-DD. Deixe vazio para enviar toda fatura emitida. Use a data em que sua contabilidade passou para o QuickBooks para não lançar faturas antigas duas vezes.",
+        "startDateHelp": "Deixe vazio para enviar toda fatura emitida. Use a data em que sua contabilidade passou para o QuickBooks para não lançar faturas antigas duas vezes.",
         "includeVehicle": "Indicar o veículo na fatura",
         "includeVehicleHelp": "Uma linha de texto acima dos itens com ano, marca, modelo, placa e quilometragem, para que a contabilidade saiba de qual carro se trata.",
         "laborItemId": "Item para linhas de mão de obra",
@@ -504,9 +508,9 @@
         "partsItemId": "Item para linhas de peças",
         "partsItemIdHelp": "Deixe vazio e um item chamado Parts será criado na sua conta de receita na primeira vez.",
         "taxCodeId": "Código de imposto para faturas tributáveis",
-        "taxCodeIdHelp": "O QuickBooks calcula o imposto a partir deste código, então escolha o que tem a mesma alíquota das suas faturas. Em uma empresa dos EUA, escolha TAX.",
+        "taxCodeIdHelp": "O QuickBooks calcula o imposto a partir deste código, então escolha o que tem a mesma alíquota das suas faturas. Uma empresa dos EUA usa TAX, a menos que você escolha outro código.",
         "zeroTaxCodeId": "Código de imposto para faturas sem imposto",
-        "zeroTaxCodeIdHelp": "Usado quando a fatura não tem imposto ou o cliente é isento. Em uma empresa dos EUA, escolha NON.",
+        "zeroTaxCodeIdHelp": "Usado quando a fatura não tem imposto ou o cliente é isento. Uma empresa dos EUA usa NON, a menos que você escolha outro código.",
         "pushPayments": "Registrar pagamentos no QuickBooks",
         "depositAccountId": "Depositar pagamentos em",
         "depositAccountIdHelp": "Deixe vazio para usar Undeposited Funds.",

+ 7 - 3
messages/ru/integrations.json

@@ -96,10 +96,14 @@
     "testPassed": "Подключение работает",
     "syncNow": "Синхронизировать сейчас",
     "syncQueued": "Синхронизация поставлена в очередь и запустится в течение минуты",
+    "pullNow": "Получить платежи сейчас",
+    "pullQueued": "Получение платежей поставлено в очередь и запустится в течение минуты",
     "backfill": "Отправить запланированные заказ-наряды",
     "backfillQueued": "Запланированные заказ-наряды за последнюю неделю и позже поставлены в очередь",
     "backfillInvoices": "Отправить выставленные счета",
     "backfillInvoicesQueued": "Счета, выставленные за последние 90 дней, поставлены в очередь",
+    "backfillInvoicesQueuedCount": "В очередь поставлено {count, plural, one {# счёт, выставленный} few {# счёта, выставленных} many {# счетов, выставленных} other {# счёта, выставленных}} за последние 90 дней",
+    "backfillInvoicesNone": "Нет счетов, выставленных за последние 90 дней, для отправки. Передаются только отправленные, опубликованные или оплаченные счета.",
     "retryQueued": "Задача снова поставлена в очередь",
     "settingsTitle": "Настройки",
     "settingsDescription": "Что синхронизировать и куда. Изменения применяются при следующей синхронизации.",
@@ -496,7 +500,7 @@
         "pushOnComplete": "Также отправлять счета, когда заказ отмечен как выполненный",
         "pushOnCompleteHelp": "Без этого счёт уходит, когда он отправлен, передан по ссылке или оплачен. С этим выполненный заказ уходит сразу и обновляется при изменениях.",
         "startDate": "Только счета с датой не раньше",
-        "startDateHelp": "ГГГГ-ММ-ДД. Оставьте пустым, чтобы отправлять все выставленные счета. Укажите дату перехода бухгалтерии на QuickBooks, чтобы старые счета не вводились дважды.",
+        "startDateHelp": "Оставьте пустым, чтобы отправлять все выставленные счета. Укажите дату перехода бухгалтерии на QuickBooks, чтобы старые счета не вводились дважды.",
         "includeVehicle": "Указывать автомобиль в счёте",
         "includeVehicleHelp": "Текстовая строка над позициями с годом, маркой, моделью, номером и пробегом, чтобы бухгалтерия знала, о какой машине речь.",
         "laborItemId": "Товар для строк работ",
@@ -504,9 +508,9 @@
         "partsItemId": "Товар для строк запчастей",
         "partsItemIdHelp": "Оставьте пустым, и в первый раз под вашим счётом доходов будет создан товар с именем Parts.",
         "taxCodeId": "Налоговый код для облагаемых счетов",
-        "taxCodeIdHelp": "QuickBooks рассчитывает налог по этому коду, поэтому выберите тот, чья ставка совпадает со ставкой в ваших счетах. В компании из США выберите TAX.",
+        "taxCodeIdHelp": "QuickBooks рассчитывает налог по этому коду, поэтому выберите тот, чья ставка совпадает со ставкой в ваших счетах. Компания в США использует TAX, если не выбрать другой код.",
         "zeroTaxCodeId": "Налоговый код для счетов без налога",
-        "zeroTaxCodeIdHelp": "Используется, когда в счёте нет налога или клиент освобождён от него. В компании из США выберите NON.",
+        "zeroTaxCodeIdHelp": "Используется, когда в счёте нет налога или клиент освобождён от него. Компания в США использует NON, если не выбрать другой код.",
         "pushPayments": "Записывать платежи в QuickBooks",
         "depositAccountId": "Зачислять платежи на",
         "depositAccountIdHelp": "Оставьте пустым, чтобы использовать Undeposited Funds.",

+ 7 - 3
messages/tr/integrations.json

@@ -96,10 +96,14 @@
     "testPassed": "Bağlantı çalışıyor",
     "syncNow": "Şimdi senkronize et",
     "syncQueued": "Senkronizasyon sıraya alındı; bir dakika içinde çalışır",
+    "pullNow": "Ödemeleri şimdi al",
+    "pullQueued": "Ödeme alma sıraya alındı; bir dakika içinde çalışır",
     "backfill": "Planlanmış iş emirlerini gönder",
     "backfillQueued": "Geçen haftadan itibaren planlanmış iş emirleri sıraya alındı",
     "backfillInvoices": "Kesilen faturaları gönder",
     "backfillInvoicesQueued": "Son 90 günde kesilen faturalar kuyruğa alındı",
+    "backfillInvoicesQueuedCount": "Son 90 günde kesilen {count, plural, one {# fatura} other {# fatura}} kuyruğa alındı",
+    "backfillInvoicesNone": "Son 90 günde kesilmiş, gönderilecek fatura yok. Yalnızca gönderilen, paylaşılan veya ödenen faturalar aktarılır.",
     "retryQueued": "İş yeniden sıraya alındı",
     "settingsTitle": "Ayarlar",
     "settingsDescription": "Neyin nereye senkronize edileceği. Değişiklikler bir sonraki senkronizasyonda uygulanır.",
@@ -496,7 +500,7 @@
         "pushOnComplete": "İş tamamlandı olarak işaretlendiğinde faturaları da gönder",
         "pushOnCompleteHelp": "Bu olmadan fatura gönderildiğinde, paylaşıldığında veya ödendiğinde aktarılır. Bununla tamamlanan iş hemen aktarılır ve değişirse güncellenir.",
         "startDate": "Yalnızca şu tarih ve sonrasındaki faturalar",
-        "startDateHelp": "YYYY-AA-GG. Kesilen her faturayı göndermek için boş bırakın. Eski faturaların iki kez girilmemesi için defterlerinizin QuickBooks'a taşındığı tarihi kullanın.",
+        "startDateHelp": "Kesilen her faturayı göndermek için boş bırakın. Eski faturaların iki kez girilmemesi için defterlerinizin QuickBooks'a taşındığı tarihi kullanın.",
         "includeVehicle": "Aracı faturada belirt",
         "includeVehicleHelp": "Kalemlerin üzerinde yıl, marka, model, plaka ve kilometreyi içeren bir metin satırı; böylece defterler hangi araç olduğunu söyler.",
         "laborItemId": "İşçilik satırları için kalem",
@@ -504,9 +508,9 @@
         "partsItemId": "Parça satırları için kalem",
         "partsItemIdHelp": "Boş bırakın; ilk seferde gelir hesabınızın altında Parts adlı bir kalem oluşturulur.",
         "taxCodeId": "Vergili faturalar için vergi kodu",
-        "taxCodeIdHelp": "QuickBooks vergiyi bu koddan hesaplar; oranı faturalarınızdaki vergi oranıyla eşleşeni seçin. ABD şirketinde TAX seçin.",
+        "taxCodeIdHelp": "QuickBooks vergiyi bu koddan hesaplar; oranı faturalarınızdaki vergi oranıyla eşleşeni seçin. ABD şirketi başka bir kod seçmediğiniz sürece TAX kullanır.",
         "zeroTaxCodeId": "Vergisiz faturalar için vergi kodu",
-        "zeroTaxCodeIdHelp": "Faturada vergi yoksa veya müşteri vergiden muafsa kullanılır. ABD şirketinde NON seçin.",
+        "zeroTaxCodeIdHelp": "Faturada vergi yoksa veya müşteri vergiden muafsa kullanılır. ABD şirketi başka bir kod seçmediğiniz sürece NON kullanır.",
         "pushPayments": "Ödemeleri QuickBooks'a kaydet",
         "depositAccountId": "Ödemeleri şuraya yatır",
         "depositAccountIdHelp": "Undeposited Funds kullanmak için boş bırakın.",

+ 41 - 0
src/__tests__/features/integrations/quickbooks-server.test.ts

@@ -491,6 +491,47 @@ describe('QuickBooks: pushing an invoice', () => {
     expect(inv?.body?.GlobalTaxCalculation).toBeUndefined()
   })
 
+  it('falls back to TAX and NON for a US company with no tax codes chosen', async () => {
+    const t = makeCtx({
+      state: { country: 'US' },
+      settings: { taxCodeId: '', zeroTaxCodeId: '' },
+      answer: emptyCompany(),
+    })
+    await connector.jobs['accounting.invoice'](t.ctx, { entityId: 'svc1' })
+    const inv = t.calls.find((c) => c.method === 'POST' && c.path.endsWith('/invoice'))
+    const lines = (inv?.body?.Line ?? []) as {
+      SalesItemLineDetail?: { TaxCodeRef?: { value: string } }
+    }[]
+    const codes = lines
+      .filter((l) => l.SalesItemLineDetail)
+      .map((l) => l.SalesItemLineDetail?.TaxCodeRef?.value)
+    expect(codes.length).toBeGreaterThan(0)
+    expect(new Set(codes)).toEqual(new Set(['TAX']))
+  })
+
+  it('offers TAX and NON ahead of the rate codes in a US company', async () => {
+    const t = makeCtx({
+      state: { country: 'US' },
+      answer: (call) =>
+        call.query.query.includes('from TaxCode')
+          ? {
+              QueryResponse: {
+                TaxCode: [
+                  { Id: '5', Name: 'Tucson' },
+                  { Id: '4', Name: 'California' },
+                ],
+              },
+            }
+          : { QueryResponse: {} },
+    })
+    expect(await connector.remoteOptions?.taxCodes(t.ctx)).toEqual([
+      { value: 'TAX', label: 'TAX (taxable)' },
+      { value: 'NON', label: 'NON (not taxable)' },
+      { value: '4', label: 'California' },
+      { value: '5', label: 'Tucson' },
+    ])
+  })
+
   it('warns when QuickBooks arrives at another total', async () => {
     const t = makeCtx({
       answer: (call) => {

+ 18 - 6
src/app/(authenticated)/settings/integrations/[connector]/connection-settings.tsx

@@ -25,6 +25,7 @@ import { AppCard } from '@/components/app-card'
 import { DocsLink } from '@/components/docs-link'
 import { Badge } from '@/components/ui/badge'
 import { Button } from '@/components/ui/button'
+import { DateInput } from '@/components/ui/date-input'
 import { Input } from '@/components/ui/input'
 import { Label } from '@/components/ui/label'
 import { Switch } from '@/components/ui/switch'
@@ -103,8 +104,8 @@ export function ConnectionSettings({
   const run = useCallback(
     async (
       key: string,
-      fn: () => Promise<{ success: boolean; error?: string } | void>,
-      done?: string
+      fn: () => Promise<{ success: boolean; error?: string; data?: unknown } | void>,
+      done?: string | ((data: unknown) => string)
     ) => {
       setBusy(key)
       try {
@@ -113,7 +114,7 @@ export function ConnectionSettings({
           toast.error(res.error || t('errors.generic'))
           return false
         }
-        if (done) toast.success(done)
+        if (done) toast.success(typeof done === 'function' ? done(res?.data) : done)
         router.refresh()
         return true
       } finally {
@@ -446,7 +447,7 @@ export function ConnectionSettings({
                   run(
                     'sync',
                     () => runIntegrationJob(manifest.id, firstSchedule),
-                    t('connection.syncQueued')
+                    isAccounting ? t('connection.pullQueued') : t('connection.syncQueued')
                   )
                 }
                 disabled={busy !== null}
@@ -456,7 +457,7 @@ export function ConnectionSettings({
                 ) : (
                   <RefreshCw className="mr-1 h-3.5 w-3.5" />
                 )}
-                {t('connection.syncNow')}
+                {isAccounting ? t('connection.pullNow') : t('connection.syncNow')}
               </Button>
             )}
             {isCalendar && (
@@ -488,7 +489,12 @@ export function ConnectionSettings({
                   run(
                     'backfill',
                     () => backfillIntegrationAccounting(manifest.id),
-                    t('connection.backfillInvoicesQueued')
+                    (data) => {
+                      const n = (data as { queued?: number } | undefined)?.queued ?? 0
+                      return n > 0
+                        ? t('connection.backfillInvoicesQueuedCount', { count: n })
+                        : t('connection.backfillInvoicesNone')
+                    }
                   )
                 }
                 disabled={busy !== null}
@@ -801,6 +807,12 @@ function SettingFieldList({
                 }
               />
             )}
+            {f.type === 'date' && (
+              <DateInput
+                value={String(values[f.key] ?? '')}
+                onChange={(v) => setValues((s) => ({ ...s, [f.key]: v }))}
+              />
+            )}
             {(f.type === 'select' || f.type === 'remote-select') && (
               <Select
                 value={String(values[f.key] ?? '')}

+ 3 - 0
src/features/integrations/Actions/integrationActions.ts

@@ -70,6 +70,8 @@ function inboundFor(
   }
 }
 
+const ISO_DAY = /^\d{4}-\d{2}-\d{2}$/
+
 const settingsSchema = z.record(
   z.string(),
   z.union([z.string().max(2000), z.number(), z.boolean()])
@@ -84,6 +86,7 @@ function cleanSettings(manifest: ConnectorManifest, raw: unknown): Record<string
     const v = input[field.key]
     if (field.type === 'boolean') clean[field.key] = Boolean(v)
     else if (field.type === 'number') clean[field.key] = Number(v)
+    else if (field.type === 'date') clean[field.key] = ISO_DAY.test(String(v)) ? String(v) : ''
     else clean[field.key] = String(v)
   }
   return clean

+ 2 - 1
src/features/integrations/Lib/types.ts

@@ -81,7 +81,8 @@ export interface SettingOption {
 
 export interface SettingField {
   key: string
-  type: 'boolean' | 'text' | 'number' | 'select' | 'remote-select'
+  /** A date is an ISO YYYY-MM-DD string, '' when unset. */
+  type: 'boolean' | 'text' | 'number' | 'date' | 'select' | 'remote-select'
   /** i18n key under integrations.connectors.<id>.settings */
   label: string
   help?: string

+ 1 - 1
src/integrations/quickbooks/manifest.ts

@@ -47,7 +47,7 @@ export const manifest: ConnectorManifest = {
     },
     {
       key: 'startDate',
-      type: 'text',
+      type: 'date',
       label: 'startDate',
       help: 'startDateHelp',
       showWhen: { key: 'pushInvoices', equals: true },

+ 19 - 3
src/integrations/quickbooks/server.ts

@@ -57,6 +57,18 @@ import {
 const PROVIDER = 'quickbooks'
 /** Change data capture reaches back at most a month. */
 const CDC_MAX_DAYS = 30
+/**
+ * The two pseudo tax codes of a US company under automated sales tax. They
+ * are what a line carries there; the rate itself comes from the customer's
+ * address. They are not TaxCode rows, so they are offered and defaulted here.
+ */
+const US_TAXABLE = 'TAX'
+const US_NON_TAXABLE = 'NON'
+const US_TAX_CODES = [
+  { value: US_TAXABLE, label: 'TAX (taxable)' },
+  { value: US_NON_TAXABLE, label: 'NON (not taxable)' },
+]
+
 /** Ledger and workshop totals may differ by rounding; beyond this the tax code is wrong. */
 const TOTAL_TOLERANCE = 0.05
 
@@ -399,8 +411,8 @@ async function pushInvoice(ctx: ConnectorContext, serviceRecordId: string): Prom
     customerEmail: customer.email,
     laborItemId: hasLabor ? await ensureItem(ctx, 'labor') : null,
     partsItemId: hasParts ? await ensureItem(ctx, 'part') : null,
-    taxCodeId: settings.taxCodeId,
-    zeroTaxCodeId: settings.zeroTaxCodeId,
+    taxCodeId: settings.taxCodeId ?? (state.country === 'US' ? US_TAXABLE : null),
+    zeroTaxCodeId: settings.zeroTaxCodeId ?? (state.country === 'US' ? US_NON_TAXABLE : null),
     globalTax: state.country !== 'US',
     currency: await currencyFor(ctx),
     timezone: ctx.timezone,
@@ -799,9 +811,13 @@ export const connector: ConnectorServer = {
         'TaxCode',
         'select Id, Name, Taxable from TaxCode where Active = true maxresults 1000'
       )
-      return codes
+      const listed = codes
         .sort((a, b) => a.Name.localeCompare(b.Name))
         .map((c) => ({ value: c.Id, label: c.Name }))
+      // A US company runs automated sales tax: TAX and NON are the codes a
+      // line carries, and the TaxCode query does not return them, only the
+      // company's own rate codes.
+      return stateOf(ctx).country === 'US' ? [...US_TAX_CODES, ...listed] : listed
     },
     async depositAccounts(ctx) {
       const accounts = await query<QboAccount>(