Bug/transaction import (#435)

* fix(invoices): drop UTKAST banner on numbered invoices and preserve logo aspect ratio

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* revert(invoices): restore UTKAST banner for drafts; keep logo aspect ratio fix

Numbered drafts intentionally surface UTKAST until manually marked sent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* revert(invoices): drop logo objectFit change

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(enable-banking): implement transaction fetch strategy and update related logic

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mattsson
2026-05-11 00:27:44 +02:00
committed by GitHub
co-authored by Claude Opus 4.7
parent 75043632de
commit ed9bdc4c00
11 changed files with 218 additions and 17 deletions
+6 -1
View File
@@ -79,6 +79,7 @@ export default function NewInvoicePage() {
const [hasBankDetails, setHasBankDetails] = useState<boolean | null>(null)
const [showBankSetup, setShowBankSetup] = useState(false)
const [accountingMethod, setAccountingMethod] = useState<'accrual' | 'cash'>('accrual')
const [oreRounding, setOreRounding] = useState<boolean>(true)
const [numberPreview, setNumberPreview] = useState<string | null>(null)
const pendingCustomerRef = useRef<Customer | null>(null)
@@ -139,7 +140,7 @@ export default function NewInvoicePage() {
if (!company?.id) return
const { data } = await supabase
.from('company_settings')
.select('invoice_default_notes, clearing_number, account_number, bankgiro, accounting_method')
.select('invoice_default_notes, clearing_number, account_number, bankgiro, accounting_method, ore_rounding')
.eq('company_id', company.id)
.single()
if (data?.invoice_default_notes) {
@@ -152,6 +153,9 @@ export default function NewInvoicePage() {
if (data?.accounting_method === 'cash' || data?.accounting_method === 'accrual') {
setAccountingMethod(data.accounting_method)
}
if (typeof data?.ore_rounding === 'boolean') {
setOreRounding(data.ore_rounding)
}
}
// Preview the next invoice number so the user can catch a mis-set
@@ -896,6 +900,7 @@ export default function NewInvoicePage() {
ourReference={pendingData?.our_reference}
notes={pendingData?.notes}
numberPreview={numberPreview}
oreRounding={oreRounding}
/>
</ConfirmationDialog>
)}
@@ -149,6 +149,10 @@ export async function GET(request: Request) {
})
)
// Do not set last_synced_at here. The session is created but no transactions
// have been fetched yet; setting it now causes the cron's first-sync 90-day
// backfill path to be skipped if the manual sync triggered by the redirect
// never lands. The first successful sync (manual or cron) will set it.
const { error: updateError } = await supabase
.from('bank_connections')
.update({
@@ -156,7 +160,6 @@ export async function GET(request: Request) {
status: 'active',
accounts_data: accountsWithBalances,
consent_expires: consentExpiresAt,
last_synced_at: new Date().toISOString(),
oauth_state: null, // Clear to prevent replay
})
.eq('id', pendingConnection.id)
@@ -156,9 +156,13 @@ export const GET = withCronContext('cron.bank_sync', async (_request, ctx) => {
.limit(1)
.maybeSingle()
const syncOptions = sieOverlap
? { skipAutoCategorization: true }
: undefined
// First sync uses strategy=longest to pull the deepest history available
// from the ASPSP. Incremental syncs skip it — the implicit default is
// faster and we already have the older data.
const syncOptions = {
...(sieOverlap ? { skipAutoCategorization: true } : {}),
...(isFirstSync ? { strategy: 'longest' as const } : {}),
}
const syncResults = await Promise.all(
accounts.map(account => syncAccountTransactions(