calc taxes on your own
This commit is contained in:
@@ -368,11 +368,108 @@ async function getBalanceSheet({ asOfDate, accountingMethod = 'Accrual' } = {})
|
||||
}
|
||||
|
||||
async function getTaxSummary({ startDate, endDate, accountingMethod = 'Accrual' } = {}) {
|
||||
const url = buildReportUrl('TaxSummary', { start_date: startDate, end_date: endDate, accounting_method: accountingMethod });
|
||||
const response = await makeQboApiCall({ url, method: 'GET' });
|
||||
const data = getJson(response);
|
||||
throwIfFault(data, 'TaxSummary report');
|
||||
return data;
|
||||
const { companyId, baseUrl } = getClientInfo();
|
||||
const qboQuery = (sql) => {
|
||||
const url = `${baseUrl}/v3/company/${companyId}/query?query=${encodeURIComponent(sql)}&minorversion=${QBO_MINOR_VERSION}`;
|
||||
return makeQboApiCall({ url, method: 'GET' });
|
||||
};
|
||||
|
||||
const rateMap = {};
|
||||
try {
|
||||
const rateRes = await qboQuery('SELECT * FROM TaxRate MAXRESULTS 1000');
|
||||
const rateData = getJson(rateRes);
|
||||
throwIfFault(rateData, 'TaxRate query');
|
||||
const rates = rateData?.QueryResponse?.TaxRate || [];
|
||||
for (const r of rates) {
|
||||
rateMap[r.Id] = {
|
||||
name: r.Name || `Tax Rate ${r.Id}`,
|
||||
rateValue: parseFloat(r.RateValue) || 0
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('TaxRate query failed, proceeding without rate names:', e.message);
|
||||
}
|
||||
|
||||
const whereClause = `TxnDate >= '${startDate}' AND TxnDate <= '${endDate}'`;
|
||||
const agg = {};
|
||||
|
||||
for (const entity of ['Invoice', 'SalesReceipt']) {
|
||||
try {
|
||||
const res = await qboQuery(`SELECT * FROM ${entity} WHERE ${whereClause} MAXRESULTS 1000`);
|
||||
const data = getJson(res);
|
||||
throwIfFault(data, `${entity} query`);
|
||||
const docs = data?.QueryResponse?.[entity] || [];
|
||||
for (const doc of docs) {
|
||||
const taxDetail = doc.TxnTaxDetail;
|
||||
if (!taxDetail || !taxDetail.TaxLine) continue;
|
||||
const taxLines = Array.isArray(taxDetail.TaxLine) ? taxDetail.TaxLine : [taxDetail.TaxLine];
|
||||
for (const line of taxLines) {
|
||||
const detail = line.TaxLineDetail;
|
||||
if (!detail || !detail.TaxRateRef) continue;
|
||||
const rateId = String(detail.TaxRateRef.value);
|
||||
const taxable = parseFloat(detail.NetAmountTaxable) || 0;
|
||||
const collected = parseFloat(line.Amount) || 0;
|
||||
if (!agg[rateId]) agg[rateId] = { taxableSales: 0, taxCollected: 0 };
|
||||
agg[rateId].taxableSales += taxable;
|
||||
agg[rateId].taxCollected += collected;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`${entity} query failed:`, e.message);
|
||||
}
|
||||
}
|
||||
|
||||
const rows = Object.entries(agg).map(([rateId, amounts]) => {
|
||||
const info = rateMap[rateId] || { name: `Tax Rate ${rateId}`, rateValue: 0 };
|
||||
const ratePct = info.rateValue.toFixed(3).replace(/0+$/, '').replace(/\.$/, '');
|
||||
return {
|
||||
type: 'Section',
|
||||
Header: {
|
||||
ColData: [
|
||||
{ value: info.name },
|
||||
{ value: '' },
|
||||
{ value: '' },
|
||||
{ value: `${ratePct}%` }
|
||||
]
|
||||
},
|
||||
Summary: {
|
||||
ColData: [
|
||||
{ value: 'Total' },
|
||||
{ value: amounts.taxableSales.toFixed(2) },
|
||||
{ value: amounts.taxCollected.toFixed(2) },
|
||||
{ value: '' }
|
||||
]
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
rows.sort((a, b) => {
|
||||
const na = a.Header.ColData[0].value;
|
||||
const nb = b.Header.ColData[0].value;
|
||||
if (na.includes('State') && !nb.includes('State')) return -1;
|
||||
if (!na.includes('State') && nb.includes('State')) return 1;
|
||||
return na.localeCompare(nb);
|
||||
});
|
||||
|
||||
return {
|
||||
Header: {
|
||||
ReportName: 'Sales Tax Liability',
|
||||
StartPeriod: startDate,
|
||||
EndPeriod: endDate,
|
||||
ReportBasis: accountingMethod
|
||||
},
|
||||
Columns: {
|
||||
Column: [
|
||||
{ ColTitle: '', ColType: 'Text' },
|
||||
{ ColTitle: 'Taxable Sales', ColType: 'Money' },
|
||||
{ ColTitle: 'Tax Collected', ColType: 'Money' },
|
||||
{ ColTitle: 'Tax Rate', ColType: 'Percent' }
|
||||
]
|
||||
},
|
||||
Rows: {
|
||||
Row: rows
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user