<freeStyleBuild _class='hudson.model.FreeStyleBuild'><action _class='hudson.model.CauseAction'><cause _class='hudson.triggers.TimerTrigger$TimerTriggerCause'><shortDescription>Started by timer</shortDescription></cause></action><action></action><action _class='hudson.plugins.git.util.BuildData'><buildsByBranchName><refsremotesorigindev _class='hudson.plugins.git.util.Build'><buildNumber>737</buildNumber><marked><SHA1>7ccda3abf09f752e54f2ad7299b242330511d169</SHA1><branch><SHA1>7ccda3abf09f752e54f2ad7299b242330511d169</SHA1><name>refs/remotes/origin/dev</name></branch></marked><revision><SHA1>7ccda3abf09f752e54f2ad7299b242330511d169</SHA1><branch><SHA1>7ccda3abf09f752e54f2ad7299b242330511d169</SHA1><name>refs/remotes/origin/dev</name></branch></revision></refsremotesorigindev></buildsByBranchName><lastBuiltRevision><SHA1>7ccda3abf09f752e54f2ad7299b242330511d169</SHA1><branch><SHA1>7ccda3abf09f752e54f2ad7299b242330511d169</SHA1><name>refs/remotes/origin/dev</name></branch></lastBuiltRevision><remoteUrl>https://github.com/younex1/erp-nuxt-frontend.git</remoteUrl><scmName></scmName></action><action></action><action></action><action _class='org.jenkinsci.plugins.displayurlapi.actions.RunDisplayAction'></action><building>false</building><displayName>#737</displayName><duration>71493</duration><estimatedDuration>71602</estimatedDuration><fullDisplayName>build-logship-frontend #737</fullDisplayName><id>737</id><inProgress>false</inProgress><keepLog>false</keepLog><number>737</number><queueId>5701</queueId><result>SUCCESS</result><timestamp>1789430400272</timestamp><url>https://jenkins.younex.de/view/all/job/build-logship-frontend/737/</url><builtOn></builtOn><changeSet _class='hudson.plugins.git.GitChangeSetList'><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>server/utils/telephony/extensions.ts</affectedPath><affectedPath>app/composables/useClickToDial.ts</affectedPath><affectedPath>app/components/DialButton.vue</affectedPath><commitId>630fc88a6a26eba7608728a395bb5fc80a4964ef</commitId><timestamp>1789370185000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Dial popover: show the PBX extension name instead of the state text — server/utils/telephony/extensions.ts reads each extension's FreePBX display name from the astdb (AMI DBGet AMPUSER/&lt;ext&gt;/cidname, covered by the reporting class already granted to the logship manager user; cached 10 min per extension, fetched on the same socket as DeviceStateList, ERP user name stays the fallback), DialButton rows now read '401 Younes' with the state carried by the coloured dot + hover tooltip only, DirectoryExtension type gains pbxName
</comment><date>2026-09-14 09:16:25 +0200</date><id>630fc88a6a26eba7608728a395bb5fc80a4964ef</id><msg>Dial popover: show the PBX extension name instead of the state text — server/utils/telephony/extensions.ts reads each extension's FreePBX display name from the astdb (AMI DBGet AMPUSER/&lt;ext&gt;/cidname, covered by the reporting class already granted to the logship manager user; cached 10 min per extension, fetched on the same socket as DeviceStateList, ERP user name stays the fallback), DialButton rows now read '401 Younes' with the state carried by the coloured dot + hover tooltip only, DirectoryExtension type gains pbxName</msg><path><editType>edit</editType><file>app/composables/useClickToDial.ts</file></path><path><editType>edit</editType><file>app/components/DialButton.vue</file></path><path><editType>edit</editType><file>server/utils/telephony/extensions.ts</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>app/components/accounting/banking/BankBackfillPanel.vue</affectedPath><affectedPath>server/api/accounting/bank-transactions/coverage.get.ts</affectedPath><affectedPath>app/assets/css/banking.css</affectedPath><affectedPath>app/components/MainNavigationMenu.vue</affectedPath><affectedPath>app/pages/accounting/banking/index.vue</affectedPath><affectedPath>app/composables/menu/admin/accounting.ts</affectedPath><affectedPath>app/assets/langs/shared.js</affectedPath><affectedPath>app/pages/accounting/bank-transactions/index.vue</affectedPath><commitId>53342fb748940c080a9c541b0d4c1a87499d5339</commitId><timestamp>1789372209000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Bank fetch page: /accounting/bank-transactions becomes the dedicated "Bankabruf" page (fetch from the bank), replacing the duplicate staged-statements/import tables — coverage table per connection (data from/to, counts, last fetch, 12-month strip green = staged / red = never fetched, click = preselect), backfill runner for past periods (months from a coverage-aware grid with "Select missing", everything since a date, free range, single day; chunks of max 31 days so PayPal's 30-day window and the proxy timeout are respected; sequential per connection + chunk, progress bar, per-chunk log, abort, retry failed, details via the fetch-result modal, dry-run toggle, hand-off to Banking → import), connection cards kept in a collapsible section; new proxy route bank-transactions/coverage.get.ts (Laravel banking/statements/coverage, fail-soft notice when not deployed); shared bk-* styles moved from the Banking page into app/assets/css/banking.css (loaded by both pages); Banking fetch modal links to the backfill page; menu labels "Bankabruf"/"Bank Fetch"; bankfetch_* translations en/de/es
</comment><date>2026-09-14 09:50:09 +0200</date><id>53342fb748940c080a9c541b0d4c1a87499d5339</id><msg>Bank fetch page: /accounting/bank-transactions becomes the dedicated "Bankabruf" page (fetch from the bank), replacing the duplicate staged-statements/import tables — coverage table per connection (data from/to, counts, last fetch, 12-month strip green = staged / red = never fetched, click = preselect), backfill runner for past periods (months from a coverage-aware grid with "Select missing", everything since a date, free range, single day; chunks of max 31 days so PayPal's 30-day window and the proxy timeout are respected; sequential per connection + chunk, progress bar, per-chunk log, abort, retry failed, details via the fetch-result modal, dry-run toggle, hand-off to Banking → import), connection cards kept in a collapsible section; new proxy route bank-transactions/coverage.get.ts (Laravel banking/statements/coverage, fail-soft notice when not deployed); shared bk-* styles moved from the Banking page into app/assets/css/banking.css (loaded by both pages); Banking fetch modal links to the backfill page; menu labels "Bankabruf"/"Bank Fetch"; bankfetch_* translations en/de/es</msg><path><editType>edit</editType><file>app/pages/accounting/banking/index.vue</file></path><path><editType>add</editType><file>app/components/accounting/banking/BankBackfillPanel.vue</file></path><path><editType>add</editType><file>server/api/accounting/bank-transactions/coverage.get.ts</file></path><path><editType>edit</editType><file>app/components/MainNavigationMenu.vue</file></path><path><editType>edit</editType><file>app/assets/langs/shared.js</file></path><path><editType>edit</editType><file>app/pages/accounting/bank-transactions/index.vue</file></path><path><editType>add</editType><file>app/assets/css/banking.css</file></path><path><editType>edit</editType><file>app/composables/menu/admin/accounting.ts</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>app/components/dashboard/RecentCallsCard.vue</affectedPath><affectedPath>app/components/dashboard/QuickContactModal.vue</affectedPath><affectedPath>app/assets/langs/shared.js</affectedPath><commitId>f810d698d77298b9a9a8e0a18b8ea93623b496bc</commitId><timestamp>1789372736000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Dashboard calls card: '+' on unmatched numbers → quick-create contact modal — new components/dashboard/QuickContactModal.vue (teleported; name required + autofocused, phone preset from the call row incl. PBX caller-id name, optional e-mail and 'als Lead anlegen' flag; creates a plain ad_user via /api/admin/users/store, not a system user, current org); RecentCallsCard remembers checked-but-unmatched numbers (null entries) so the '+' only shows after the ES match finished, and stores the created user as the number's contact locally so the row flips to the contact menu without waiting for the ad_user index sync; rcc_add_contact/qcm_* translations en/de/es
</comment><date>2026-09-14 09:58:56 +0200</date><id>f810d698d77298b9a9a8e0a18b8ea93623b496bc</id><msg>Dashboard calls card: '+' on unmatched numbers → quick-create contact modal — new components/dashboard/QuickContactModal.vue (teleported; name required + autofocused, phone preset from the call row incl. PBX caller-id name, optional e-mail and 'als Lead anlegen' flag; creates a plain ad_user via /api/admin/users/store, not a system user, current org); RecentCallsCard remembers checked-but-unmatched numbers (null entries) so the '+' only shows after the ES match finished, and stores the created user as the number's contact locally so the row flips to the contact menu without waiting for the ad_user index sync; rcc_add_contact/qcm_* translations en/de/es</msg><path><editType>add</editType><file>app/components/dashboard/QuickContactModal.vue</file></path><path><editType>edit</editType><file>app/components/dashboard/RecentCallsCard.vue</file></path><path><editType>edit</editType><file>app/assets/langs/shared.js</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>server/api/commission/parcels/dhl/multi.post.ts</affectedPath><affectedPath>server/api/commission/parcels/dhl/index.post.ts</affectedPath><affectedPath>server/api/commission/parcels/dpd/multi.post.ts</affectedPath><affectedPath>server/api/commission/parcels/dpd/index.post.ts</affectedPath><commitId>e644ded9fd4885ca7e5be18f1d3c638d0b687e12</commitId><timestamp>1789373944000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>DPD labels: carry address2 (Adresszusatz) like DHL — dpd/index + dpd/multi now map body.address2 into the recipient: name2 when no company/c/o is set, otherwise the company keeps name2 and address2 goes to contact (the only other printed DPD line, 35 chars), plus a data-only comment mirror (70); &lt;contact&gt; emitted after &lt;city&gt; and &lt;comment&gt; after &lt;email&gt; per the DPD XSD order. DHL index/multi cap consignee name2/name3 at 50 chars so over-long values are truncated instead of rejected. Frontend unchanged (commission.vue already sends both fields to both carriers).
</comment><date>2026-09-14 10:19:04 +0200</date><id>e644ded9fd4885ca7e5be18f1d3c638d0b687e12</id><msg>DPD labels: carry address2 (Adresszusatz) like DHL — dpd/index + dpd/multi now map body.address2 into the recipient: name2 when no company/c/o is set, otherwise the company keeps name2 and address2 goes to contact (the only other printed DPD line, 35 chars), plus a data-only comment mirror (70); &lt;contact&gt; emitted after &lt;city&gt; and &lt;comment&gt; after &lt;email&gt; per the DPD XSD order. DHL index/multi cap consignee name2/name3 at 50 chars so over-long values are truncated instead of rejected. Frontend unchanged (commission.vue already sends both fields to both carriers).</msg><path><editType>edit</editType><file>server/api/commission/parcels/dhl/index.post.ts</file></path><path><editType>edit</editType><file>server/api/commission/parcels/dpd/multi.post.ts</file></path><path><editType>edit</editType><file>server/api/commission/parcels/dpd/index.post.ts</file></path><path><editType>edit</editType><file>server/api/commission/parcels/dhl/multi.post.ts</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>server/utils/telephony/transcriptionResponse.ts</affectedPath><affectedPath>server/api/telephony/recordings/transcribe-status.get.ts</affectedPath><affectedPath>app/components/telephony/CallRecordingsModal.vue</affectedPath><affectedPath>server/api/telephony/recordings/transcribe.post.ts</affectedPath><affectedPath>server/utils/telephony/recordings.ts</affectedPath><commitId>72610850d43102cc0e14ac7cf6ef1b5db716ace6</commitId><timestamp>1789375913000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Call recordings: async whisper transcription — transcribe.post.ts starts the job, waits max 20 s and answers 202 pending for anything longer (the edge nginx cuts requests at 60 s, long calls used to 504 while whisper kept running); new transcribe-status.get.ts polls the disk state (pending marker &lt;file&gt;.pending.json shared across PM2 instances, cache file = done, marker error = failed); shared statusResponse() in transcriptionResponse.ts; CallRecordingsModal polls every 3 s up to 25 min and shows the elapsed time
</comment><date>2026-09-14 10:51:53 +0200</date><id>72610850d43102cc0e14ac7cf6ef1b5db716ace6</id><msg>Call recordings: async whisper transcription — transcribe.post.ts starts the job, waits max 20 s and answers 202 pending for anything longer (the edge nginx cuts requests at 60 s, long calls used to 504 while whisper kept running); new transcribe-status.get.ts polls the disk state (pending marker &lt;file&gt;.pending.json shared across PM2 instances, cache file = done, marker error = failed); shared statusResponse() in transcriptionResponse.ts; CallRecordingsModal polls every 3 s up to 25 min and shows the elapsed time</msg><path><editType>edit</editType><file>server/utils/telephony/recordings.ts</file></path><path><editType>edit</editType><file>app/components/telephony/CallRecordingsModal.vue</file></path><path><editType>add</editType><file>server/utils/telephony/transcriptionResponse.ts</file></path><path><editType>add</editType><file>server/api/telephony/recordings/transcribe-status.get.ts</file></path><path><editType>edit</editType><file>server/api/telephony/recordings/transcribe.post.ts</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>reference/~$roadsurfer_Fulfillment_Anfrage_Preisblatt_LogYou.xlsx</affectedPath><affectedPath>reference/roadsurfer_Fulfillment_Anfrage_Preisblatt_LogYou.xlsx</affectedPath><commitId>14d0e08b8c0a28cd535aeb98b9273a2ce1dfb557</commitId><timestamp>1789375913000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Roadsurfer price sheet: update workbook, drop stray Excel lock file
</comment><date>2026-09-14 10:51:53 +0200</date><id>14d0e08b8c0a28cd535aeb98b9273a2ce1dfb557</id><msg>Roadsurfer price sheet: update workbook, drop stray Excel lock file</msg><path><editType>delete</editType><file>reference/~$roadsurfer_Fulfillment_Anfrage_Preisblatt_LogYou.xlsx</file></path><path><editType>edit</editType><file>reference/roadsurfer_Fulfillment_Anfrage_Preisblatt_LogYou.xlsx</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>server/api/accounting/amazon-ads/connect.get.ts</affectedPath><affectedPath>.gitignore</affectedPath><affectedPath>server/api/accounting/amazon-ads/document.get.ts</affectedPath><affectedPath>server/api/accounting/amazon-ads/import.post.ts</affectedPath><affectedPath>server/api/accounting/amazon-ads/disconnect.post.ts</affectedPath><affectedPath>server/utils/amazonAds/types.ts</affectedPath><affectedPath>.env-dev</affectedPath><affectedPath>nuxt.config.ts</affectedPath><affectedPath>server/api/invoices/lexoffice-upload.post.ts</affectedPath><affectedPath>server/api/accounting/amazon-ads/status.get.ts</affectedPath><affectedPath>server/api/oauth/amazon-ads/callback.get.ts</affectedPath><affectedPath>app/components/AgGrid.vue</affectedPath><affectedPath>app/assets/langs/shared.js</affectedPath><affectedPath>server/utils/amazonAds/routeShared.ts</affectedPath><affectedPath>server/utils/amazonAds/importInvoice.ts</affectedPath><affectedPath>server/utils/amazonAds/parseInvoicePdf.ts</affectedPath><affectedPath>server/utils/amazonAds/adsApi.ts</affectedPath><affectedPath>.env</affectedPath><affectedPath>server/api/accounting/amazon-ads/profile.put.ts</affectedPath><affectedPath>reference/INVOICE-503111M5PA26.pdf</affectedPath><affectedPath>app/pages/accounting/amazon-ads-invoices/index.vue</affectedPath><affectedPath>server/utils/invoiceOriginalPdf.ts</affectedPath><affectedPath>server/api/accounting/amazon-ads/invoices.get.ts</affectedPath><affectedPath>reference/test-scripts/amazon-ads-parse.mjs</affectedPath><affectedPath>server/api/accounting/amazon-ads/upload.post.ts</affectedPath><affectedPath>app/components/MainNavigationMenu.vue</affectedPath><affectedPath>server/api/accounting/amazon-ads/profiles.get.ts</affectedPath><affectedPath>server/utils/amazonAds/adsStore.ts</affectedPath><affectedPath>app/composables/menu/admin/accounting.ts</affectedPath><affectedPath>server/api/accounting/amazon-ads/void.post.ts</affectedPath><affectedPath>.env-prod</affectedPath><commitId>0f630bc593490f322597f096f15bc84851b5a3c0</commitId><timestamp>1789375913000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Amazon Ads invoices → Eingangsrechnungen: new page /accounting/amazon-ads-invoices lists Sponsored-Ads invoices (Amazon Ads API when connected — LWA consent flow, profile picker, GET /invoices + /invoices/{id} + /billing/documents PDF — or console PDFs dropped on the page and parsed server-side), lets the user tick which ones to import and books each as a completed AP invoice on the fixed vendor 1043801 (org *): one charge line per campaign (default charge Werbekosten), tax by rate so GrandTotal = Amazon gross, DocumentNo/POReference = Amazon invoice no., duplicate guard, original Amazon PDF attached under PO_Invoice; Storno action voids + renames the number (&lt;no&gt;-VOID-&lt;id&gt;) so the same invoice can be re-imported; booked/Lexoffice status comes from iDempiere (vendor AP invoices matched by number). Lexoffice upload: purchase invoices now upload the attached vendor original instead of the Jasper print (no ZUGFeRD on foreign documents) and requireOriginal:true skips invoices without one (used by the Ads page). Store data/amazon-ads.db + PDF cache data/amazon-ads/ (git-ignored); AMAZON_ADS_* env keys (empty = PDF-upload mode until the Ads API approval exists); AgGrid wrapper registers RowGroupingPanelModule (error #200 on every grid page); menu + en/de/es labels; parser dev script reference/test-scripts/amazon-ads-parse.mjs + sample invoice
</comment><date>2026-09-14 10:51:53 +0200</date><id>0f630bc593490f322597f096f15bc84851b5a3c0</id><msg>Amazon Ads invoices → Eingangsrechnungen: new page /accounting/amazon-ads-invoices lists Sponsored-Ads invoices (Amazon Ads API when connected — LWA consent flow, profile picker, GET /invoices + /invoices/{id} + /billing/documents PDF — or console PDFs dropped on the page and parsed server-side), lets the user tick which ones to import and books each as a completed AP invoice on the fixed vendor 1043801 (org *): one charge line per campaign (default charge Werbekosten), tax by rate so GrandTotal = Amazon gross, DocumentNo/POReference = Amazon invoice no., duplicate guard, original Amazon PDF attached under PO_Invoice; Storno action voids + renames the number (&lt;no&gt;-VOID-&lt;id&gt;) so the same invoice can be re-imported; booked/Lexoffice status comes from iDempiere (vendor AP invoices matched by number). Lexoffice upload: purchase invoices now upload the attached vendor original instead of the Jasper print (no ZUGFeRD on foreign documents) and requireOriginal:true skips invoices without one (used by the Ads page). Store data/amazon-ads.db + PDF cache data/amazon-ads/ (git-ignored); AMAZON_ADS_* env keys (empty = PDF-upload mode until the Ads API approval exists); AgGrid wrapper registers RowGroupingPanelModule (error #200 on every grid page); menu + en/de/es labels; parser dev script reference/test-scripts/amazon-ads-parse.mjs + sample invoice</msg><path><editType>add</editType><file>server/api/accounting/amazon-ads/profiles.get.ts</file></path><path><editType>add</editType><file>server/api/accounting/amazon-ads/document.get.ts</file></path><path><editType>add</editType><file>server/utils/invoiceOriginalPdf.ts</file></path><path><editType>add</editType><file>reference/INVOICE-503111M5PA26.pdf</file></path><path><editType>edit</editType><file>.env</file></path><path><editType>edit</editType><file>app/composables/menu/admin/accounting.ts</file></path><path><editType>add</editType><file>server/utils/amazonAds/parseInvoicePdf.ts</file></path><path><editType>edit</editType><file>app/components/AgGrid.vue</file></path><path><editType>add</editType><file>server/api/accounting/amazon-ads/connect.get.ts</file></path><path><editType>add</editType><file>app/pages/accounting/amazon-ads-invoices/index.vue</file></path><path><editType>edit</editType><file>app/components/MainNavigationMenu.vue</file></path><path><editType>add</editType><file>server/utils/amazonAds/importInvoice.ts</file></path><path><editType>add</editType><file>server/api/accounting/amazon-ads/invoices.get.ts</file></path><path><editType>edit</editType><file>.env-dev</file></path><path><editType>edit</editType><file>.env-prod</file></path><path><editType>edit</editType><file>app/assets/langs/shared.js</file></path><path><editType>add</editType><file>server/utils/amazonAds/types.ts</file></path><path><editType>add</editType><file>server/utils/amazonAds/routeShared.ts</file></path><path><editType>add</editType><file>server/api/accounting/amazon-ads/disconnect.post.ts</file></path><path><editType>add</editType><file>server/utils/amazonAds/adsStore.ts</file></path><path><editType>add</editType><file>server/api/accounting/amazon-ads/import.post.ts</file></path><path><editType>edit</editType><file>.gitignore</file></path><path><editType>add</editType><file>server/api/accounting/amazon-ads/upload.post.ts</file></path><path><editType>add</editType><file>reference/test-scripts/amazon-ads-parse.mjs</file></path><path><editType>add</editType><file>server/utils/amazonAds/adsApi.ts</file></path><path><editType>add</editType><file>server/api/oauth/amazon-ads/callback.get.ts</file></path><path><editType>edit</editType><file>nuxt.config.ts</file></path><path><editType>edit</editType><file>server/api/invoices/lexoffice-upload.post.ts</file></path><path><editType>add</editType><file>server/api/accounting/amazon-ads/status.get.ts</file></path><path><editType>add</editType><file>server/api/accounting/amazon-ads/profile.put.ts</file></path><path><editType>add</editType><file>server/api/accounting/amazon-ads/void.post.ts</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>app/components/dashboard/RecentCallsCard.vue</affectedPath><affectedPath>app/components/dashboard/QuickContactModal.vue</affectedPath><affectedPath>server/api/admin/users/search.get.ts</affectedPath><affectedPath>app/pages/sales/orders/[id]/view.vue</affectedPath><affectedPath>server/utils/telephony/cdr.ts</affectedPath><affectedPath>app/pages/sales/orders/[id]/edit.vue</affectedPath><affectedPath>server/api/telephony/recent-calls.get.ts</affectedPath><affectedPath>app/assets/langs/shared.js</affectedPath><commitId>b99b7ac21f59acb46845cd37905cf64ad2f389e4</commitId><timestamp>1789378079000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Sales order ship-to name + dashboard calls card improvements

Sales orders: edit.vue only fetched order data in onMounted, so switching
between order tabs via the in-app tab bar (router.push into the same
keep-alive'd component, only :id changes) kept showing the previously loaded
order's data — including its business partner — until a hard reload. Added a
route.params.id watcher (loadOrderData()) mirroring the existing fix on
sales/invoices and sales/customer-rma edit pages. Also added the ship-to
recipient name (C_BPartner_Location_ID.Name — the same field the orders grid
shows as "Name", which can legitimately differ from the business partner's
own Name) to the read-only order view.vue page, which was missing it
entirely; edit.vue's OrderForm.vue already displayed it correctly.

Dashboard "Letzte Anrufe" card: the extension badge and duration/missed
label were side-by-side in a fixed-width column that could overflow into
neighboring text. Stacked them vertically instead and gave rows a bit more
height. Added server-side search (number/name) and pagination — cdr.ts's
recentCalls() now takes offset/search/direction and returns total +
missedTotal (so the missed-count badge stays accurate regardless of the
active direction tab or page).

Quick-contact modal (dashboard "+" on unmatched calls): added a "search
existing contact" panel above the create-new form, so a call can be linked
to an existing ad_user/lead instead of always creating a duplicate. Scoped
to the caller's own organization by default ("search all organizations" to
widen), with a type filter (All/Lead/External/Internal) mirroring the
site's existing Users/Leads/External Users split. New
GET /api/admin/users/search endpoint backs it; picking a result only PUTs
the call's phone number onto the existing contact when it isn't already on
file, to avoid clobbering an existing different number.
</comment><date>2026-09-14 11:27:59 +0200</date><id>b99b7ac21f59acb46845cd37905cf64ad2f389e4</id><msg>Sales order ship-to name + dashboard calls card improvements</msg><path><editType>edit</editType><file>app/pages/sales/orders/[id]/view.vue</file></path><path><editType>edit</editType><file>server/utils/telephony/cdr.ts</file></path><path><editType>edit</editType><file>app/components/dashboard/QuickContactModal.vue</file></path><path><editType>add</editType><file>server/api/admin/users/search.get.ts</file></path><path><editType>edit</editType><file>app/components/dashboard/RecentCallsCard.vue</file></path><path><editType>edit</editType><file>server/api/telephony/recent-calls.get.ts</file></path><path><editType>edit</editType><file>app/pages/sales/orders/[id]/edit.vue</file></path><path><editType>edit</editType><file>app/assets/langs/shared.js</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>app/components/sales/InvoiceListFilters.vue</affectedPath><affectedPath>app/pages/sales/invoices/index.vue</affectedPath><affectedPath>app/components/sales/InvoiceAction.vue</affectedPath><affectedPath>app/components/AgGrid/Invoices/AgInvoiceKind.vue</affectedPath><affectedPath>server/api/invoices/so.get.ts</affectedPath><affectedPath>app/assets/langs/shared.js</affectedPath><commitId>852e5a139e7dc3c8d4e43fa24f46d603c71b710d</commitId><timestamp>1789379089000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Sales invoices: merge in purchase (AP) invoices, incl. Amazon Ads imports

server/api/invoices/so.get.ts dropped its IsSOTrx-only filter (kept the
existing DocStatus CO/CL/DR restriction) so /sales/invoices now returns both
sales and purchase invoices — including the Amazon Ads AP invoices booked via
/accounting/amazon-ads-invoices, which land in c_invoice like any other
vendor invoice. Route name/URL kept as-is to avoid touching every caller.

New "Type" grid column (AgInvoiceKind.vue) tags each row AR/AR-CM/AP/AP-CM
from C_Invoice.DocBaseType (the same field lexoffice-upload.post.ts already
keys its AR/AP branching on), right after the document-number column.

InvoiceListFilters.vue gained two segmented filters: Receivables/Payables
(side, derived from IsSOTrx / the C_DocTypeTarget_ID 1000006 "AP CreditMemo
used as a customer credit note" exception — same convention as
accounting/opos) and Lexoffice upload status (uploaded/not uploaded), both
applied client-side alongside the existing fulfillment/payment/amount
filters so the grand-total row and counts stay consistent.

The existing bulk Lexoffice upload button needed no changes — the shared
lexoffice-upload.post.ts route already branches on DocBaseType per invoice
(original vendor PDF for AP, Jasper print for AR) and processes mixed AR/AP
id batches correctly; it just never had AP rows to select from before.

Fixed InvoiceAction.vue's row-menu edit/duplicate handlers, which always
navigated to the sales-invoice pages — now they branch on isSOTrx to
/procurements/invoices/{id}/{edit,duplicate} for AP rows, matching the
branching AgLink.vue's document-number link already had.

Note: this route has no $top cap (pre-existing), so removing the AR-only
restriction roughly doubles the worst-case row count for orgs with a long
purchase-invoice history — worth watching if the page gets sluggish.
</comment><date>2026-09-14 11:44:49 +0200</date><id>852e5a139e7dc3c8d4e43fa24f46d603c71b710d</id><msg>Sales invoices: merge in purchase (AP) invoices, incl. Amazon Ads imports</msg><path><editType>edit</editType><file>app/assets/langs/shared.js</file></path><path><editType>edit</editType><file>app/components/sales/InvoiceListFilters.vue</file></path><path><editType>edit</editType><file>app/pages/sales/invoices/index.vue</file></path><path><editType>edit</editType><file>app/components/sales/InvoiceAction.vue</file></path><path><editType>edit</editType><file>server/api/invoices/so.get.ts</file></path><path><editType>add</editType><file>app/components/AgGrid/Invoices/AgInvoiceKind.vue</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>app/pages/users/leads/[id]/edit.vue</affectedPath><commitId>9b08ac127dfe1f98967ced8227f64c07868a1db3</commitId><timestamp>1789379322000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Lead page: move Aufnahmen button out of the offer/contract CTA group

The "Aufnahmen" (call recordings) button sat in the top-right CTA cluster
alongside Angebot/Vertrag/SEPA/Onboarding, but it isn't part of that
offer/contract workflow — it's phone-call history. Moved it next to the
phone number / DialButton in the contact-chips row instead, gated on the
lead having a phone number (nothing to match recordings against otherwise).
The compact top-toolbar icon button (MobileActionsMenu) already had its own
"Aufnahmen" entry and is unchanged.
</comment><date>2026-09-14 11:48:42 +0200</date><id>9b08ac127dfe1f98967ced8227f64c07868a1db3</id><msg>Lead page: move Aufnahmen button out of the offer/contract CTA group</msg><path><editType>edit</editType><file>app/pages/users/leads/[id]/edit.vue</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>app/components/dashboard/RecentCallsCard.vue</affectedPath><affectedPath>app/components/DialButton.vue</affectedPath><affectedPath>app/assets/langs/shared.js</affectedPath><commitId>39f1dfd5739eef2e6173ff543b20fba47bca5fa3</commitId><timestamp>1789379675000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>DialButton: opt-in Recordings toggle (play-only) in the dial popover

Adds a showRecordings prop that puts a headset icon in the popover header
next to Close. Toggling it switches the popover body to a compact list of
FreePBX recordings matched to `number` (GET /api/telephony/recordings, same
endpoint CallRecordingsModal.vue uses on contact pages, called here with
just `numbers` — no source/recordId, so it works for numbers with no known
contact too) — date, direction, duration and a play button only, no
transcription/download clutter. Off by default everywhere; enabled on both
DialButton usages in the dashboard's "Letzte Anrufe" card, so clicking a
call's number now offers a quick way to listen to past recordings for that
number right from the dial popover.
</comment><date>2026-09-14 11:54:35 +0200</date><id>39f1dfd5739eef2e6173ff543b20fba47bca5fa3</id><msg>DialButton: opt-in Recordings toggle (play-only) in the dial popover</msg><path><editType>edit</editType><file>app/assets/langs/shared.js</file></path><path><editType>edit</editType><file>app/components/DialButton.vue</file></path><path><editType>edit</editType><file>app/components/dashboard/RecentCallsCard.vue</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>app/components/dashboard/RecentCallsCard.vue</affectedPath><commitId>3a2aa7e776b1ecd670ff8e1f0abb8a4de7311b04</commitId><timestamp>1789379818000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Recent calls card: stack date above number, give the name its own full line

The date used to be its own fixed 62px grid column, squeezing how much
width the number/name column got. Moved it to sit above the number instead
(inside the same column), so the name — which can run considerably longer
than the number — gets the full row width on its own line rather than
sharing it with a separate date column.
</comment><date>2026-09-14 11:56:58 +0200</date><id>3a2aa7e776b1ecd670ff8e1f0abb8a4de7311b04</id><msg>Recent calls card: stack date above number, give the name its own full line</msg><path><editType>edit</editType><file>app/components/dashboard/RecentCallsCard.vue</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>server/api/materials/locators/priority-recommendations.get.ts</affectedPath><commitId>d9627b7266e6432d9febb322babb26fcc4f62970</commitId><timestamp>1789380713000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Locator priorities: exclude locators not allowed for shipping

M_LocatorType.IsAvailableForShipping=false locators (return bins,
quarantine, reconditioning input, ...) are dropped before building
pick-order conflicts/proposals, since shipment generation never picks
from them anyway.
</comment><date>2026-09-14 12:11:53 +0200</date><id>d9627b7266e6432d9febb322babb26fcc4f62970</id><msg>Locator priorities: exclude locators not allowed for shipping</msg><path><editType>edit</editType><file>server/api/materials/locators/priority-recommendations.get.ts</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>app/components/DialButton.vue</affectedPath><affectedPath>app/assets/langs/shared.js</affectedPath><commitId>c1fb76e4b48ea72b198182db778fce1fb2a4892b</commitId><timestamp>1789383931000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>DialButton: fix recordings that appeared to play but stayed silent

Chrome's &lt;audio&gt; element does not behave like a normal failed request when
the recordings route errors out (e.g. the PBX recordings service returns a
JSON error body instead of audio): no 'error' event ever fires and
.play()'s promise never settles either — it just sits at
networkState=LOADING/readyState=HAVE_NOTHING with paused=false forever.
Since the row's play/stop icon was driven only by a manually-toggled ref,
a failed load looked exactly like "still playing" with no sound and no
way to tell it failed. Add a stall-timeout guard (6s) that aborts the
hung request, resets the button and shows an inline error message when
playable data never arrives; canplay/playing clear the timer on success.
</comment><date>2026-09-14 13:05:31 +0200</date><id>c1fb76e4b48ea72b198182db778fce1fb2a4892b</id><msg>DialButton: fix recordings that appeared to play but stayed silent</msg><path><editType>edit</editType><file>app/assets/langs/shared.js</file></path><path><editType>edit</editType><file>app/components/DialButton.vue</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>app/components/AgGrid/Invoices/AgInvoiceKind.vue</affectedPath><commitId>182290a4e2c2f6c96174f4a55e9d7c30acf5855c</commitId><timestamp>1789383938000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>AgInvoiceKind: fix AP/AR tags never actually getting their colors

The tag colors never rendered: this component is used as an AG Grid
cellRenderer, and its &lt;style scoped&gt; block never reached the rendered
elements (they carried no data-v-* attribute at all), so every tag
silently fell back to Bulma's plain grey .tag look regardless of AR/AP/
credit-memo type — the same gap already documented for AG Grid image
cell renderers. Move the styling to a non-scoped block keyed off a
dedicated .ag-ikind-tag marker class (so it can't leak onto the many
other Bulma .tag elements elsewhere in the app), and switch from thin
outlined tags to solid-filled ones so AP vs AR reads at a glance while
scanning a long invoice grid.
</comment><date>2026-09-14 13:05:38 +0200</date><id>182290a4e2c2f6c96174f4a55e9d7c30acf5855c</id><msg>AgInvoiceKind: fix AP/AR tags never actually getting their colors</msg><path><editType>edit</editType><file>app/components/AgGrid/Invoices/AgInvoiceKind.vue</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>server/api/invoices/lexoffice-upload.post.ts</affectedPath><affectedPath>app/components/sales/LexofficeCategoryModal.vue</affectedPath><commitId>3648fbba0e22b85d8209ea8ec5b961f204aff7e9</commitId><timestamp>1789383946000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Lexoffice upload: default AP invoices into Ausgaben, not the general inbox

Without an explicit category, uploads went through Lexoffice's plain
Files-drop, which auto-creates its own uncategorized draft voucher — it
never lands as a filed Einnahmen/Ausgaben entry, just a general/pending
item in Lexoffice's own inbox. AR invoices only looked correctly filed
under Einnahmen because someone picked a category for them every time,
which goes through the Vouchers API instead.

Add a third modal option, "Mit Standardkategorie hochladen": books a
real voucher via the same Vouchers API as an explicit category, using a
generic catch-all per direction (Einnahmen for AR/AR-CM, Sonstige
Ausgaben for AP/AP-CM) resolved per invoice so a mixed bulk upload still
files each one correctly. The true "Ohne Kategorie hochladen" (plain,
uncategorized Files-drop) option is unchanged and still available.

Also fixes APC (AP credit memo) incorrectly booking as voucher type
purchaseinvoice instead of purchasecreditnote.
</comment><date>2026-09-14 13:05:46 +0200</date><id>3648fbba0e22b85d8209ea8ec5b961f204aff7e9</id><msg>Lexoffice upload: default AP invoices into Ausgaben, not the general inbox</msg><path><editType>edit</editType><file>server/api/invoices/lexoffice-upload.post.ts</file></path><path><editType>edit</editType><file>app/components/sales/LexofficeCategoryModal.vue</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>app/pages/accounting/bank-transactions/index.vue</affectedPath><affectedPath>app/assets/langs/shared.js</affectedPath><commitId>d7464e740863297d158a64b96ec8573d0e755371</commitId><timestamp>1789391406000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Bank fetch coverage: show import progress per month, not just staged

Coverage cells only reflected whether any statement was staged for a
month; add the imported/open counts the coverage endpoint already
returns so a month reads green only once fully imported, amber while
partially imported, with the count shown. Also surface the imported
count as a pill on the connection row, next to the existing pending one.
</comment><date>2026-09-14 15:10:06 +0200</date><id>d7464e740863297d158a64b96ec8573d0e755371</id><msg>Bank fetch coverage: show import progress per month, not just staged</msg><path><editType>edit</editType><file>app/pages/accounting/bank-transactions/index.vue</file></path><path><editType>edit</editType><file>app/assets/langs/shared.js</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>.env-dev</affectedPath><affectedPath>.gitignore</affectedPath><affectedPath>server/api/telephony/cid-lookup/[number].get.ts</affectedPath><affectedPath>nuxt.config.ts</affectedPath><affectedPath>server/utils/elasticHelper.ts</affectedPath><affectedPath>.env</affectedPath><affectedPath>.env-prod</affectedPath><commitId>3c67c7ed036f479cad2a91044c687bb5dbfbe6a4</commitId><timestamp>1789399518000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Add asterisk lookup endpoint

Squashed to drop an accidentally committed 134MB HAR capture file
that was blocking the push (GitHub's 100MB file size limit); also
gitignore *.har so this can't recur.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_013G7aDXCyYUwGgTG81QTP8E
</comment><date>2026-09-14 17:25:18 +0200</date><id>3c67c7ed036f479cad2a91044c687bb5dbfbe6a4</id><msg>Add asterisk lookup endpoint</msg><path><editType>edit</editType><file>.env</file></path><path><editType>edit</editType><file>server/utils/elasticHelper.ts</file></path><path><editType>edit</editType><file>.env-prod</file></path><path><editType>edit</editType><file>.gitignore</file></path><path><editType>add</editType><file>server/api/telephony/cid-lookup/[number].get.ts</file></path><path><editType>edit</editType><file>nuxt.config.ts</file></path><path><editType>edit</editType><file>.env-dev</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>server/api/offers/conditions/index.post.ts</affectedPath><affectedPath>server/utils/offers/quotePdf.ts</affectedPath><affectedPath>app/components/offers/QuoteModal.vue</affectedPath><affectedPath>app/assets/langs/shared.js</affectedPath><affectedPath>app/composables/useOfferQuote.ts</affectedPath><commitId>0d5c36c95d22b6066ed5d0718459bb0e6e13c578</commitId><timestamp>1789403035000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Quote: configurable grading pricing (time/fixed + description) and save-draft button

Grading is now priced by time/effort or a fixed price with a freetext
description printed as a subtext, instead of a flat by-effort checkbox.
Also adds a Save button on the quote modal to persist offer_conditions
without sending the quote.
</comment><date>2026-09-14 18:23:55 +0200</date><id>0d5c36c95d22b6066ed5d0718459bb0e6e13c578</id><msg>Quote: configurable grading pricing (time/fixed + description) and save-draft button</msg><path><editType>edit</editType><file>app/assets/langs/shared.js</file></path><path><editType>add</editType><file>server/api/offers/conditions/index.post.ts</file></path><path><editType>edit</editType><file>app/components/offers/QuoteModal.vue</file></path><path><editType>edit</editType><file>server/utils/offers/quotePdf.ts</file></path><path><editType>edit</editType><file>app/composables/useOfferQuote.ts</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>server/utils/offers/quotePdf.ts</affectedPath><affectedPath>app/pages/index.vue</affectedPath><affectedPath>app/components/offers/QuoteModal.vue</affectedPath><affectedPath>server/utils/offers/offerConditions.ts</affectedPath><affectedPath>app/composables/useOfferQuote.ts</affectedPath><affectedPath>app/assets/langs/shared.js</affectedPath><commitId>26efb3a1498df891c0853f9e44aae23876a7713c</commitId><timestamp>1789403770000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Quote: customer-requirements checklist; dashboard: leads card quick actions

Add a "Kundenanforderungen" section to the quote modal — freetext bullet
points each answered possible/not possible (green check / red X) or with
a freetext answer, printed as a checklist in the PDF.

Also add "create lead" and "open all leads" icon buttons to the dashboard's
latest-leads card header.
</comment><date>2026-09-14 18:36:10 +0200</date><id>26efb3a1498df891c0853f9e44aae23876a7713c</id><msg>Quote: customer-requirements checklist; dashboard: leads card quick actions</msg><path><editType>edit</editType><file>server/utils/offers/quotePdf.ts</file></path><path><editType>edit</editType><file>app/components/offers/QuoteModal.vue</file></path><path><editType>edit</editType><file>app/composables/useOfferQuote.ts</file></path><path><editType>edit</editType><file>server/utils/offers/offerConditions.ts</file></path><path><editType>edit</editType><file>app/pages/index.vue</file></path><path><editType>edit</editType><file>app/assets/langs/shared.js</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>app/components/settings/OrderSourceForm.vue</affectedPath><affectedPath>server/api/oauth/amazon/test-connection.post.ts</affectedPath><affectedPath>.env-prod</affectedPath><commitId>82e20b0c80024eabe37fea705ff9d11134cfbf58</commitId><timestamp>1789417063000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>Amazon: switch central OAuth app to Published, fix test-connection + credential UI

Order source 1000026 stopped importing because the previous central Amazon app
("logship", Draft) hit its mandatory 180-day LWA Client Secret rotation deadline
(2026-09-12) — LWA still authenticated fine, but every SP-API call was denied.
Reconnecting the seller's own authorization doesn't rotate the app's secret, so
that never fixed it. Standardized the central app on "LogShip App" (Published)
instead, matching what order source 1000000 already used successfully.

Also:
- test-connection.post.ts: report failure (with Amazon's real error text) when
  every SP-API endpoint is denied, instead of always defaulting to a misleading
  "missing Tax Invoicing role" message.
- OrderSourceForm.vue: hide the raw Client ID / Client Secret / Refresh Token
  fields for Amazon by default (Connect/Reconnect manages them automatically);
  only reveal them behind an explicit "uses its own separate Amazon Developer
  app" toggle.
</comment><date>2026-09-14 22:17:43 +0200</date><id>82e20b0c80024eabe37fea705ff9d11134cfbf58</id><msg>Amazon: switch central OAuth app to Published, fix test-connection + credential UI</msg><path><editType>edit</editType><file>app/components/settings/OrderSourceForm.vue</file></path><path><editType>edit</editType><file>.env-prod</file></path><path><editType>edit</editType><file>server/api/oauth/amazon/test-connection.post.ts</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>server/api/sales/sis/order-sources.get.ts</affectedPath><affectedPath>server/api/sales/sis/listings.get.ts</affectedPath><affectedPath>app/composables/menu/admin/sales.ts</affectedPath><affectedPath>app/components/MainNavigationMenu.vue</affectedPath><affectedPath>app/pages/sales/sis/index.vue</affectedPath><affectedPath>server/api/sales/sis/offers.post.ts</affectedPath><affectedPath>server/utils/amazonSpApi.ts</affectedPath><affectedPath>server/utils/sisMatching.ts</affectedPath><affectedPath>server/api/sales/sis/price-update.post.ts</affectedPath><affectedPath>app/assets/langs/shared.js</affectedPath><commitId>7ccda3abf09f752e54f2ad7299b242330511d169</commitId><timestamp>1789424614000</timestamp><author><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></author><authorEmail>info@younex.de</authorEmail><comment>SIS: new Amazon pricing control page — compare internal vs Amazon price/qty, Buy Box, fees, push corrected prices

Admin-only page under Sales comparing internal price/stock against what's
live on Amazon for each Amazon order source, with a one-click price push
back to Amazon. New Amazon SP-API surface in amazonSpApi.ts: bulk merchant
listings report (Reports API, the source of truth for "what's on Amazon"),
Listings Items API read/patch, Product Pricing API (Buy Box), Fees Estimate
API. Product matching is SKU-first (Value/SKU) with ASIN as fallback, via
sisMatching.ts. Verified end-to-end against live production data, including
a real price push (Amazon's Listings Items PATCH turned out to be async
despite returning immediately, so pushes poll briefly then trust the
accepted submission, with a short-lived overlay so a subsequent bulk report
refresh can't revert a just-pushed price before Amazon's own report catches
up).
</comment><date>2026-09-15 00:23:34 +0200</date><id>7ccda3abf09f752e54f2ad7299b242330511d169</id><msg>SIS: new Amazon pricing control page — compare internal vs Amazon price/qty, Buy Box, fees, push corrected prices</msg><path><editType>add</editType><file>server/api/sales/sis/price-update.post.ts</file></path><path><editType>edit</editType><file>server/utils/amazonSpApi.ts</file></path><path><editType>edit</editType><file>app/composables/menu/admin/sales.ts</file></path><path><editType>add</editType><file>server/api/sales/sis/order-sources.get.ts</file></path><path><editType>add</editType><file>server/utils/sisMatching.ts</file></path><path><editType>add</editType><file>app/pages/sales/sis/index.vue</file></path><path><editType>edit</editType><file>app/assets/langs/shared.js</file></path><path><editType>add</editType><file>server/api/sales/sis/listings.get.ts</file></path><path><editType>add</editType><file>server/api/sales/sis/offers.post.ts</file></path><path><editType>edit</editType><file>app/components/MainNavigationMenu.vue</file></path></item><kind>git</kind></changeSet><culprit><absoluteUrl>https://jenkins.younex.de/user/info</absoluteUrl><fullName>info</fullName></culprit></freeStyleBuild>