Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(PC-33051)[API] feat: Generate invoices with correct wording for OA. #15108

Merged
merged 1 commit into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions api/src/pcapi/core/finance/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
from pcapi.domain import reimbursement
from pcapi.models import db
from pcapi.models import feature
from pcapi.models.feature import FeatureToggle
from pcapi.repository import is_managed_transaction
from pcapi.repository import mark_transaction_as_invalid
from pcapi.repository import on_commit
Expand Down Expand Up @@ -2431,7 +2432,14 @@ def _prepare_invoice_context(invoice: models.Invoice, batch: models.CashflowBatc

period_start, period_end = get_invoice_period(batch.cutoff)

ff_wording = {
"venue": "structure" if FeatureToggle.WIP_ENABLE_OFFER_ADDRESS.is_active() else "lieu",
"venues": "Structures" if FeatureToggle.WIP_ENABLE_OFFER_ADDRESS.is_active() else "Lieux",
"offerer": "Entité juridique" if FeatureToggle.WIP_ENABLE_OFFER_ADDRESS.is_active() else "Structure",
}

return dict(
ff_wording=ff_wording,
invoice=invoice,
is_caledonian_invoice=is_caledonian_invoice,
cashflows=cashflows,
Expand Down
2 changes: 1 addition & 1 deletion api/src/pcapi/templates/invoices/debit_note.html
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@
</svg>
<h1>Note de débit</h1>{% set currency_symbol = "CFP" if is_caledonian_invoice else "€" %}
<div class="customerInfo">
<p><b>Structure :</b> {{ bank_account.offerer.name }} - {{ bank_account.offerer.identifier }}</p>
<p><b>{{ ff_wording.offerer }} :</b> {{ bank_account.offerer.name }} - {{ bank_account.offerer.identifier }}</p>
<p><b>Compte bancaire :</b> {{ bank_account_label }} - {{ bank_account_iban }}</p>
</div>
<h3 class="coloredTitle">
Expand Down
6 changes: 3 additions & 3 deletions api/src/pcapi/templates/invoices/invoice.html
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@
</svg>
<h1>Justificatif de remboursement</h1>{% set currency_symbol = "CFP" if is_caledonian_invoice else "€" %}
<div class="customerInfo">
<p><b>Structure :</b> {{ bank_account.offerer.name }} - {{ bank_account.offerer.identifier }}</p>
<p><b>{{ ff_wording.offerer }} :</b> {{ bank_account.offerer.name }} - {{ bank_account.offerer.identifier }}</p>
<p><b>Compte bancaire :</b> {{ bank_account_label }} - {{ bank_account_iban }}</p>
</div>
<h3 class="coloredTitle">
Expand Down Expand Up @@ -285,11 +285,11 @@ <h3>Règlements effectués correspondant au montant remboursé</h3>
</tbody>
</table>
{% endif %}
<h3>Montant des remboursements par lieu{{ ' et détail de la part individuelle et collective' if not is_caledonian_invoice else '' }}</h3>
<h3>Montant des remboursements par {{ ff_wording.venue }}{{ ' et détail de la part individuelle et collective' if not is_caledonian_invoice else '' }}</h3>
<table class="reimbursementByVenueTable">
<thead>
<tr>
<th>Lieux</th>
<th>{{ ff_wording.venues }}</th>
<th>Montant des réservations validées (TTC)</th>
<th>Montant de la contribution offreur (TTC)</th>
<th>Incidents (TTC)</th>
Expand Down
9 changes: 6 additions & 3 deletions api/tests/core/finance/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from pcapi.core.offers import factories as offers_factories
from pcapi.core.subscription.ubble import api as ubble_subscription_api
from pcapi.core.testing import assert_num_queries
from pcapi.core.testing import override_features
from pcapi.core.testing import override_settings
from pcapi.core.users import api as users_api
from pcapi.core.users import factories as users_factories
Expand Down Expand Up @@ -2350,7 +2351,8 @@ def test_invoices_csv_commercial_gesture():


@pytest.mark.usefixtures("clean_temp_files", "css_font_http_request_mock")
def test_invoice_pdf_commercial_gesture(monkeypatch):
@pytest.mark.parametrize("with_oa", [True, False])
def test_invoice_pdf_commercial_gesture(monkeypatch, with_oa):
invoice_htmls = []

def _store_invoice_pdf(invoice_storage_id, invoice_html) -> None:
Expand Down Expand Up @@ -2429,7 +2431,8 @@ def _store_invoice_pdf(invoice_storage_id, invoice_html) -> None:

cutoff = datetime.datetime.utcnow() + datetime.timedelta(days=1)
batch = api.generate_cashflows_and_payment_files(cutoff)
api.generate_invoices_and_debit_notes(batch)
with override_features(WIP_ENABLE_OFFER_ADDRESS=with_oa):
api.generate_invoices_and_debit_notes(batch)

invoices = models.Invoice.query.all()
assert len(invoices) == 1
Expand Down Expand Up @@ -2522,7 +2525,7 @@ def _store_invoice_pdf(invoice_storage_id, invoice_html) -> None:
assert reimbursement_by_venue_row["Dont offres collectives (TTC)"] == "0,00 €"
assert reimbursement_by_venue_row["Dont offres individuelles (TTC)"] == "308,40 €"
assert reimbursement_by_venue_row["Incidents (TTC)"] == "10,10 €"
assert reimbursement_by_venue_row["Lieux"] == venue.name
assert reimbursement_by_venue_row["Structures" if with_oa else "Lieux"] == venue.name
assert reimbursement_by_venue_row["Montant de la contribution offreur (TTC)"] == "0,00 €"
assert reimbursement_by_venue_row["Montant des réservations validées (TTC)"] == "298,30 €"
assert reimbursement_by_venue_row["Montant remboursé (TTC)"] == "308,40 €"
Expand Down
66 changes: 52 additions & 14 deletions api/tests/core/finance/test_api_legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from pcapi.core.offerers import models as offerers_models
from pcapi.core.offers import factories as offers_factories
from pcapi.core.testing import assert_num_queries
from pcapi.core.testing import override_features
from pcapi.core.users import factories as users_factories
from pcapi.models import db
from pcapi.routes.backoffice.finance import validation
Expand Down Expand Up @@ -1124,7 +1125,8 @@ def test_invoices_csv_commercial_gesture():


@pytest.mark.usefixtures("clean_temp_files", "css_font_http_request_mock")
def test_invoice_pdf_commercial_gesture(monkeypatch):
@pytest.mark.parametrize("with_oa", [True, False])
def test_invoice_pdf_commercial_gesture(monkeypatch, with_oa):
invoice_htmls = []

def _store_invoice_pdf(invoice_storage_id, invoice_html) -> None:
Expand Down Expand Up @@ -1203,7 +1205,8 @@ def _store_invoice_pdf(invoice_storage_id, invoice_html) -> None:

cutoff = datetime.datetime.utcnow() + datetime.timedelta(days=1)
batch = api.generate_cashflows_and_payment_files(cutoff)
api.generate_invoices_and_debit_notes_legacy(batch)
with override_features(WIP_ENABLE_OFFER_ADDRESS=with_oa):
api.generate_invoices_and_debit_notes_legacy(batch)

invoices = models.Invoice.query.all()
assert len(invoices) == 1
Expand Down Expand Up @@ -1296,7 +1299,7 @@ def _store_invoice_pdf(invoice_storage_id, invoice_html) -> None:
assert reimbursement_by_venue_row["Dont offres collectives (TTC)"] == "0,00 €"
assert reimbursement_by_venue_row["Dont offres individuelles (TTC)"] == "308,40 €"
assert reimbursement_by_venue_row["Incidents (TTC)"] == "10,10 €"
assert reimbursement_by_venue_row["Lieux"] == venue.name
assert reimbursement_by_venue_row["Structures" if with_oa else "Lieux"] == venue.name
assert reimbursement_by_venue_row["Montant de la contribution offreur (TTC)"] == "0,00 €"
assert reimbursement_by_venue_row["Montant des réservations validées (TTC)"] == "298,30 €"
assert reimbursement_by_venue_row["Montant remboursé (TTC)"] == "308,40 €"
Expand Down Expand Up @@ -2363,7 +2366,7 @@ def test_common_name_is_not_empty_public_name(self):
class GenerateDebitNoteHtmlTest:
TEST_FILES_PATH = pathlib.Path(tests.__path__[0]) / "files"

def generate_and_compare_invoice(self, bank_account, venue, expected_generated_file_name):
def generate_and_compare_invoice(self, bank_account, venue, expected_generated_file_name, with_oa):
user = users_factories.RichBeneficiaryFactory()
book_offer = offers_factories.OfferFactory(venue=venue, subcategoryId=subcategories.LIVRE_PAPIER.id)
factories.CustomReimbursementRuleFactory(amount=2850, offer=book_offer)
Expand Down Expand Up @@ -2427,7 +2430,8 @@ def generate_and_compare_invoice(self, bank_account, venue, expected_generated_f
is_debit_note=True,
)
batch = models.CashflowBatch.query.get(batch.id)
invoice_html = api._generate_debit_note_html(invoice, batch)
with override_features(WIP_ENABLE_OFFER_ADDRESS=with_oa):
invoice_html = api._generate_debit_note_html(invoice, batch)

with open(self.TEST_FILES_PATH / "invoice" / expected_generated_file_name, "r", encoding="utf-8") as f:
expected_invoice_html = f.read()
Expand All @@ -2444,20 +2448,34 @@ def test_basics(self, invoice_data):

del stocks # we don't need it

self.generate_and_compare_invoice(bank_account, venue, "rendered_debit_note.html")
self.generate_and_compare_invoice(bank_account, venue, "rendered_debit_note.html", False)

def test_basics_with_oa(self, invoice_data):
bank_account, stocks, venue = invoice_data

del stocks # we don't need it

self.generate_and_compare_invoice(bank_account, venue, "rendered_debit_note_with_oa.html", True)

def test_nc_invoice(self, invoice_nc_data):
bank_account, stocks, venue = invoice_nc_data

del stocks # we don't need it

self.generate_and_compare_invoice(bank_account, venue, "rendered_nc_debit_note.html")
self.generate_and_compare_invoice(bank_account, venue, "rendered_nc_debit_note.html", False)

def test_nc_invoice_with_oa(self, invoice_nc_data):
bank_account, stocks, venue = invoice_nc_data

del stocks # we don't need it

self.generate_and_compare_invoice(bank_account, venue, "rendered_nc_debit_note_with_oa.html", True)


class GenerateInvoiceHtmlTest:
TEST_FILES_PATH = pathlib.Path(tests.__path__[0]) / "files"

def generate_and_compare_invoice(self, stocks, bank_account, venue, is_caledonian):
def generate_and_compare_invoice(self, stocks, bank_account, venue, is_caledonian, with_oa):
user = users_factories.RichBeneficiaryFactory()
book_offer = offers_factories.OfferFactory(venue=venue, subcategoryId=subcategories.LIVRE_PAPIER.id)
factories.CustomReimbursementRuleFactory(amount=2850, offer=book_offer)
Expand Down Expand Up @@ -2549,8 +2567,16 @@ def generate_and_compare_invoice(self, stocks, bank_account, venue, is_caledonia
)

batch = models.CashflowBatch.query.get(batch.id)
invoice_html = api._generate_invoice_html(invoice, batch)
expected_generated_file_name = "rendered_nc_invoice.html" if is_caledonian else "rendered_invoice.html"
with override_features(WIP_ENABLE_OFFER_ADDRESS=with_oa):
invoice_html = api._generate_invoice_html(invoice, batch)

if with_oa:
expected_generated_file_name = (
"rendered_nc_invoice_with_oa.html" if is_caledonian else "rendered_invoice_with_oa.html"
)
else:
expected_generated_file_name = "rendered_nc_invoice.html" if is_caledonian else "rendered_invoice.html"

with open(self.TEST_FILES_PATH / "invoice" / expected_generated_file_name, "r", encoding="utf-8") as f:
expected_invoice_html = f.read()

Expand All @@ -2574,7 +2600,7 @@ def generate_and_compare_invoice(self, stocks, bank_account, venue, is_caledonia
)
assert expected_invoice_html == invoice_html

def test_basics(self, invoice_data):
def basics(self, invoice_data, with_oa):
bank_account, stocks, venue = invoice_data
pricing_point = offerers_models.Venue.query.get(venue.current_pricing_point_id)
only_educational_venue = offerers_factories.VenueFactory(
Expand Down Expand Up @@ -2607,9 +2633,21 @@ def test_basics(self, invoice_data):
api.price_event(collective_booking_finance_event1)
api.price_event(collective_booking_finance_event2)

self.generate_and_compare_invoice(stocks, bank_account, venue, False)
self.generate_and_compare_invoice(stocks, bank_account, venue, False, with_oa)

def test_nc_invoice(self, invoice_nc_data):
def test_basics(self, invoice_data):
self.basics(invoice_data, False)

def test_basics_with_oa(self, invoice_data):
self.basics(invoice_data, True)

def nc_invoice(self, invoice_nc_data, with_oa):
bank_account, stocks, venue = invoice_nc_data

self.generate_and_compare_invoice(stocks, bank_account, venue, True)
self.generate_and_compare_invoice(stocks, bank_account, venue, True, with_oa)

def test_nc_invoice(self, invoice_nc_data):
self.nc_invoice(invoice_nc_data, False)

def test_nc_invoice_with_oa(self, invoice_nc_data):
self.nc_invoice(invoice_nc_data, True)
Loading
Loading