Compare commits
2 commits
827565838f
...
f8aab05cb7
| Author | SHA1 | Date | |
|---|---|---|---|
| f8aab05cb7 | |||
| 04f67a786f |
8 changed files with 96 additions and 4 deletions
|
|
@ -1,3 +1,7 @@
|
|||
# 0.8.2
|
||||
|
||||
* Add ability to delete an invoice via 'Manage Invoices' dialog
|
||||
|
||||
# 0.8.1
|
||||
|
||||
* Fix bold/italic/strikethrough styling in certain conditions when toolbar action is used.
|
||||
|
|
|
|||
|
|
@ -2392,6 +2392,18 @@ class DBManager:
|
|||
(document_id, invoice_id),
|
||||
)
|
||||
|
||||
def delete_invoice(self, invoice_id: int) -> None:
|
||||
"""Delete an invoice.
|
||||
|
||||
Related invoice line items and invoice ↔ time log links are removed via
|
||||
ON DELETE CASCADE.
|
||||
"""
|
||||
with self.conn:
|
||||
self.conn.execute(
|
||||
"DELETE FROM invoices WHERE id = ?",
|
||||
(invoice_id,),
|
||||
)
|
||||
|
||||
def time_logs_for_range(
|
||||
self,
|
||||
project_id: int,
|
||||
|
|
|
|||
|
|
@ -1065,6 +1065,10 @@ class InvoicesDialog(QDialog):
|
|||
btn_row = QHBoxLayout()
|
||||
btn_row.addStretch(1)
|
||||
|
||||
delete_btn = QPushButton(strings._("delete"))
|
||||
delete_btn.clicked.connect(self._on_delete_clicked)
|
||||
btn_row.addWidget(delete_btn)
|
||||
|
||||
close_btn = QPushButton(strings._("close"))
|
||||
close_btn.clicked.connect(self.accept)
|
||||
btn_row.addWidget(close_btn)
|
||||
|
|
@ -1073,6 +1077,68 @@ class InvoicesDialog(QDialog):
|
|||
|
||||
self._reload_invoices()
|
||||
|
||||
# ----------------------------------------------------------------- deletion
|
||||
|
||||
def _on_delete_clicked(self) -> None:
|
||||
"""Delete the currently selected invoice."""
|
||||
row = self.table.currentRow()
|
||||
if row < 0:
|
||||
sel = self.table.selectionModel().selectedRows()
|
||||
if sel:
|
||||
row = sel[0].row()
|
||||
if row < 0:
|
||||
QMessageBox.information(
|
||||
self,
|
||||
strings._("delete"),
|
||||
strings._("invoice_required"),
|
||||
)
|
||||
return
|
||||
|
||||
base_item = self.table.item(row, self.COL_NUMBER)
|
||||
if base_item is None:
|
||||
return
|
||||
|
||||
inv_id = base_item.data(Qt.ItemDataRole.UserRole)
|
||||
if not inv_id:
|
||||
return
|
||||
|
||||
invoice_number = (base_item.text() or "").strip() or "?"
|
||||
proj_item = self.table.item(row, self.COL_PROJECT)
|
||||
project_name = (proj_item.text() if proj_item is not None else "").strip()
|
||||
|
||||
label = strings._("delete")
|
||||
prompt = (
|
||||
f"{label} '{invoice_number}'"
|
||||
+ (f" ({project_name})" if project_name else "")
|
||||
+ "?"
|
||||
)
|
||||
|
||||
resp = QMessageBox.question(
|
||||
self,
|
||||
label,
|
||||
prompt,
|
||||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||
QMessageBox.StandardButton.No,
|
||||
)
|
||||
if resp != QMessageBox.StandardButton.Yes:
|
||||
return
|
||||
|
||||
# Remove any automatically created due-date reminder.
|
||||
if self.cfg.reminders:
|
||||
self._remove_invoice_due_reminder(row, int(inv_id))
|
||||
|
||||
try:
|
||||
self._db.delete_invoice(int(inv_id))
|
||||
except Exception as e:
|
||||
QMessageBox.warning(
|
||||
self,
|
||||
strings._("error"),
|
||||
f"Failed to delete invoice: {e}",
|
||||
)
|
||||
return
|
||||
|
||||
self._reload_invoices()
|
||||
|
||||
# ------------------------------------------------------------------ helpers
|
||||
|
||||
def _reload_projects(self) -> None:
|
||||
|
|
|
|||
|
|
@ -436,5 +436,6 @@
|
|||
"invoice_invalid_date_format": "Invalid date format",
|
||||
"invoice_invalid_tax_rate": "The tax rate is invalid",
|
||||
"invoice_no_items": "There are no items in the invoice",
|
||||
"invoice_number_required": "An invoice number is required"
|
||||
"invoice_number_required": "An invoice number is required",
|
||||
"invoice_required": "Please select a specific invoice before trying to delete an invoice."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -432,5 +432,6 @@
|
|||
"invoice_invalid_date_format": "Format de date invalide",
|
||||
"invoice_invalid_tax_rate": "Le taux de TVA est invalide",
|
||||
"invoice_no_items": "La facture ne contient aucun article",
|
||||
"invoice_number_required": "Un numéro de facture est requis"
|
||||
"invoice_number_required": "Un numéro de facture est requis",
|
||||
"invoice_required": "Veuillez sélectionner une facture spécifique avant d'essayer de supprimer la facture."
|
||||
}
|
||||
|
|
|
|||
6
debian/changelog
vendored
6
debian/changelog
vendored
|
|
@ -1,3 +1,9 @@
|
|||
bouquin (0.8.2) unstable; urgency=medium
|
||||
|
||||
* Add ability to delete an invoice via 'Manage Invoices' dialog
|
||||
|
||||
-- Miguel Jacq <mig@mig5.net> Wed, 31 Dec 2025 16:00:00 +1100
|
||||
|
||||
bouquin (0.8.1) unstable; urgency=medium
|
||||
|
||||
* Fix bold/italic/strikethrough styling in certain conditions when toolbar action is used.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "bouquin"
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
description = "Bouquin is a simple, opinionated notebook application written in Python, PyQt and SQLCipher."
|
||||
authors = ["Miguel Jacq <mig@mig5.net>"]
|
||||
readme = "README.md"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
# provides the Python distribution/module as "sqlcipher4". To keep Fedora's
|
||||
# auto-generated python3dist() Requires correct, we rewrite the dependency key in
|
||||
# pyproject.toml at build time.
|
||||
%global upstream_version 0.8.1
|
||||
%global upstream_version 0.8.2
|
||||
|
||||
Name: bouquin
|
||||
Version: %{upstream_version}
|
||||
|
|
@ -82,6 +82,8 @@ install -Dpm 0644 bouquin/icons/bouquin.svg %{buildroot}%{_datadir}/icons/hicolo
|
|||
%{_datadir}/icons/hicolor/scalable/apps/bouquin.svg
|
||||
|
||||
%changelog
|
||||
* Wed Dec 31 2025 Miguel Jacq <mig@mig5.net> - %{version}-%{release}
|
||||
- Add ability to delete an invoice via 'Manage Invoices' dialog
|
||||
* Fri Dec 26 2025 Miguel Jacq <mig@mig5.net> - %{version}-%{release}
|
||||
- Fix bold/italic/strikethrough styling in certain conditions when toolbar action is used.
|
||||
- Move a code block or collapsed section (or generally, anything after a checkbox line until the next checkbox line) when moving an unchecked checkbox line to another day.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue