2 Commits (fced87d23a0af2f07baa4a88680a72f7fb19bb49)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
1056dddc62 |
Take the address by field, fix the customer type, ask why they leave
**The billing address was one textarea**, so what landed in it was whatever somebody typed: a postcode on the street line, a city with no postcode, no country at all. It is four fields now — street, postcode, town, country — in the customer's settings and in the console's customer editor, which had its own free-text copy of the same field and would have had an operator's correction silently reverted the next time the customer saved. `customers.billing_address` is neither dropped nor parsed: guessing which line of an existing block is the street would put a postcode where a street belongs on a document nobody can correct afterwards. It becomes the COMPOSED form, rewritten from the fields on every save, so IssueInvoice and everything else that reads it keep working, and a record nobody has re-saved keeps the block it always had. **The customer type is fixed once it is on record.** It decides the fourteen-day right of withdrawal, and a business able to set itself to "Privatperson" on this page is a business able to withdraw from a contract it may not withdraw from. Registration asks the question; this page reports the answer, and saveProfile refuses to answer it a second time — in the component, not by hiding a radio, because a form that hides a control has never stopped anybody who can post to /livewire/update. A record created before the question existed may still be given one, once. The panel is a fact rather than a form now, which is also what was odd about it, and the sentence about who has the right of withdrawal is gone. **Cancelling asks why.** A reason from a fixed list, required, with a note beside it that "Sonstiges" cannot go without — the one fact worth having about a departure, asked at the only moment the customer is looking at the question. It lands on the contract (`cancel_reason`, `cancel_reason_note`). And where the fourteen days are still running, the dialogue offers the WITHDRAWAL as a way out of itself rather than as one more reason inside it: withdrawing ends the service the same day and sends the whole amount back, cancelling keeps the term that was paid for, and somebody entitled to the first should not lose it by taking the second unasked. A business is never offered it — WithdrawalRight answers that, not the template. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
|
|
|
f00cbf18d3 |
Let an operator correct a customer's details
tests / pest (push) Failing after 7m59s
Details
tests / assets (push) Successful in 23s
Details
tests / release (push) Has been skipped
Details
The console could show them and not touch them, so a moved office or a new contact person meant impersonating the customer or editing the database by hand. Both are worse than a form. R20: a modal, opened from the Stammdaten tab, authorising again and reading the record itself rather than trusting anything the browser hydrated. Most of the work is in what saving must NOT quietly do. The customer type is never reset to "nobody asked". The field opens on "leave unchanged" precisely so that saving an address correction cannot undo it — that answer decides whether a withdrawal right exists, and losing it silently would be the expensive kind of quiet. A changed VAT number is unverified from the moment it is stored — the verification is bound to the value, so that happens by itself — but `vat_id_verified_value` is left alone: it is the record of what WAS checked, and clearing it would destroy the evidence rather than the claim. The address is also the sign-in address and the key inbound mail is matched by, so changing it moves the linked portal login in the same transaction and puts it back to unverified, which is what Laravel's own profile update does for the same reason: nobody has shown they can read the new address. No mail is sent from here — the portal asks for the confirmation at the next sign-in, and a mail an operator did not knowingly send is a surprise. Three addresses are refused: one belonging to an operator (R21 — no index spans the two tables, so it is checked), one belonging to another customer, and one belonging to somebody else's user row, which can outlive or predate a matching customer. Not offered here, each for its own reason: `status`, because suspending has consequences for access and a lifecycle switch hidden among address fields is one somebody flips by accident; `stripe_customer_id`, because a wrong one does not move a contract, it points our records at somebody else's payments; the brand fields, because the customer sets those for themselves and an operator overwriting a logo is not a correction. There is a test that fails if any of them appears — with the comments stripped first, since the class documents at length why they are absent and that documentation is not the offence. This repository has fallen into that trap three times. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |