feat: support unassigned purchases and allocation status
Allow month-only purchases to start finance plans. Keep unbudgeted posts distinct from explicit zero rules in overspend reporting.
This commit is contained in:
@@ -49,6 +49,7 @@ export function PurchaseDialog({ monthId, purchase, trigger }: Props) {
|
||||
.sort((a, b) => a.order - b.order);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [detachBill, setDetachBill] = useState(false);
|
||||
const [draft, setDraft] = useState<PurchaseDraft>(() =>
|
||||
purchase ? fromPurchase(purchase) : emptyDraft(monthId, activePosts[0]?.id ?? ""),
|
||||
);
|
||||
@@ -68,6 +69,7 @@ export function PurchaseDialog({ monthId, purchase, trigger }: Props) {
|
||||
const errors = bulkMode ? validateBulk(bulk) : validatePurchase(draft);
|
||||
|
||||
function reset() {
|
||||
setDetachBill(false);
|
||||
setDraft(
|
||||
purchase ? fromPurchase(purchase) : emptyDraft(monthId, activePosts[0]?.id ?? ""),
|
||||
);
|
||||
@@ -86,7 +88,10 @@ export function PurchaseDialog({ monthId, purchase, trigger }: Props) {
|
||||
const created = bulkMode ? toPurchases(bulk) : null;
|
||||
void mutate((data) => {
|
||||
if (created) for (const p of created) addPurchase(data, p);
|
||||
else if (purchase) updatePurchase(data, purchase.id, toPurchase(draft));
|
||||
else if (purchase) updatePurchase(data, purchase.id, {
|
||||
...toPurchase(draft),
|
||||
...(detachBill ? { source: undefined } : {}),
|
||||
});
|
||||
else addPurchase(data, toPurchase(draft));
|
||||
}).then((saved) => {
|
||||
if (!saved) return;
|
||||
@@ -166,7 +171,7 @@ export function PurchaseDialog({ monthId, purchase, trigger }: Props) {
|
||||
setBulk((b) => ({ ...b, postId }));
|
||||
}}
|
||||
>
|
||||
<option value="">Choose a post…</option>
|
||||
<option value="">No post (unassigned)</option>
|
||||
{activePosts.map((post) => (
|
||||
<option key={post.id} value={post.id}>
|
||||
{post.name}
|
||||
@@ -301,6 +306,17 @@ export function PurchaseDialog({ monthId, purchase, trigger }: Props) {
|
||||
|
||||
<SplitEditor draft={draft} posts={activePosts} onChange={setDraft} />
|
||||
|
||||
{purchase?.source && (
|
||||
<label className="flex items-start gap-2 text-sm">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={detachBill}
|
||||
onChange={(event) => setDetachBill(event.target.checked)}
|
||||
/>
|
||||
<span>Unlink from bill. The occurrence will show as expected again.</span>
|
||||
</label>
|
||||
)}
|
||||
|
||||
<PlanEditor draft={draft} onChange={setDraft} />
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user