Onze mòduls després d'aquell print("Hola, món!"), tens totes les peces sobre la taula: un paquet papyrus amb models, errors i tests, dues maneres de servir-lo per la web i un laboratori de dades que respon preguntes de negoci. El que encara no has fet és construir un sistema sencer tu sol, des d'un full de requisits fins a un lliurable. Aquest salt — de seguir lliçons a decidir, implementar i verificar sense xarxa — és exactament el que separa qui "ha fet un curs de Python" de qui "sap construir amb Python". El mòdul 12 és el teu examen final autodidacta: Papyrus Online, la versió integral de la llibreria de l'Anna. Aquesta primera lliçó defineix el contracte: què es construeix, com es mesura que està bé, i què queda deliberadament fora.

Contingut

  1. Per què un projecte integrador (i per què ara)
  2. Què és Papyrus Online: el sistema complet
  3. Requisits funcionals (RF1-RF7)
  4. Requisits no funcionals (RNF1-RNF4)
  5. Criteris d'acceptació mesurables
  6. Abast: el que queda fora (i per què)
  7. Dos itineraris: API Flask o web Django
  8. Mapa de requisits → mòduls del curs
  9. Com treballar aquest mòdul

Per què un projecte integrador

Fins ara, cada lliçó et donava el problema i la manera de resoldre'l. A la feina real, ningú no ho fa, això: reps requisits (sovint vagues), i les decisions — quina estructura, quins errors, què provar — són teves. Un projecte integrador entrena tres músculs que cap lliçó aïllada no pot entrenar:

  • Decisió sota ambigüitat: triar entre alternatives vàlides i assumir-ne les conseqüències (itinerari A o B, dict o llista, JSON o CSV).
  • Integració: les peces que funcionen soles fallen juntes de maneres noves — rutes relatives que es trenquen, floats que no quadren, imports circulars. Depurar entre capes és una habilitat diferent de depurar dins d'una funció.
  • Tancament: decidir quan una cosa està "feta" i lliurar-la. Els projectes personals solen morir al 80 %; aquest mòdul et dona criteris d'acceptació explícits perquè el 100 % existeixi i sigui assolible.

Les lliçons d'aquest mòdul no et donaran tot el codi. Et donaran estructura, esquelets, contractes i punts de control; tu implementes. Allà on una peça integri massa coses alhora (com el servei de vendes), hi haurà solució completa comentada. Per a la resta, solucions orientatives: si la teva és diferent però passa els criteris, és tan vàlida com la nostra.

Què és Papyrus Online

Papyrus Online és el sistema que l'Anna faria servir de veritat: gestiona el catàleg i els socis, registra vendes aplicant tarifes i cupons, ho persisteix tot a disc, ho exposa per una interfície web i genera cada mes un informe amb dades i un gràfic.

flowchart LR
    subgraph Interficie["Interfície"]
        API["API Flask (itinerari A)<br/>o web Django (itinerari B)"]
    end
    subgraph Core["Paquet papyrus (domini)"]
        M["models: Llibre, Soci"]
        S["serveis: vendes, cupons"]
        E["errors: jerarquia ErrorPapyrus"]
    end
    subgraph Persistencia["Persistència"]
        J["cataleg.json / socis.json"]
        C["vendes.csv"]
    end
    subgraph Analisi["Anàlisi"]
        I["informe mensual<br/>pandas + Matplotlib"]
    end
    API --> Core
    Core --> Persistencia
    Persistencia --> Analisi
    Core -. "logging → dades/papyrus.log" .-> L[(papyrus.log)]

Fixa't en la direcció de les fletxes: la interfície usa el core, mai a l'inrevés. És la regla que M10 anomenava "la web tradueix, el paquet resol", i a 12-02 la convertirem en arquitectura.

Requisits funcionals

Numerats per poder referir-nos-hi durant tot el mòdul (a 12-04 cadascun tindrà el seu test):

  • RF1 — Gestió de catàleg (CRUD): alta, consulta, modificació i baixa de llibres. Cada llibre té títol, autor, preu i estoc. No hi pot haver dos llibres amb el mateix títol (el títol és la clau, com a tot el curs).
  • RF2 — Socis i descomptes: registre de socis amb codi únic (format NOM-NNN, com LLUIS-001). Un soci identificat obté el 5 % de descompte (DESCOMPTE_SOCI = 0.05) sobre el preu amb IVA. Un codi inexistent s'ha de rebutjar amb SociInvalidError.
  • RF3 — Vendes amb cupons i control d'estoc: vendre N unitats d'un títol verifica l'estoc (si en falta, EstocInsuficientError i no es modifica res), aplica tarifa de soci si escau i cupó si escau (PAPYRUS10 → 10 %, SOCI5 → 5 %; cupó desconegut → CupoInvalidError), descompta estoc i registra la venda.
  • RF4 — Persistència: catàleg i socis en JSON; vendes en CSV amb columnes data,titol,unitats,quantia. El sistema arrenca carregant els fitxers i no perd dades si una escriptura falla a mitges (guardat atòmic, com el TransaccioCataleg de M8).
  • RF5 — Interfície (a triar): itinerari A, API REST amb Flask (GET/POST/PUT/DELETE /api/llibres, POST /api/vendes, errors 404/409/400 en JSON); itinerari B, web Django (llistat, detall, formulari de venda amb ModelForm, admin actiu).
  • RF6 — Informe de dades mensual: a partir del CSV de vendes, un script genera: total d'unitats i quantia del mes, top 3 de títols, comparativa per dia de la setmana, i un gràfic guardat com a PNG. Amb vendes_2026.csv ha de reproduir els números canònics de M11 (520 unitats gen-jun, dissabte com a millor dia amb 130).
  • RF7 — Registre (logging): tota venda, error de negoci i operació de persistència queda registrada a dades/papyrus.log amb el nivell adequat (INFO operacions, WARNING rebuigs de negoci, ERROR errors tècnics).

Requisits no funcionals

  • RNF1 — Tests: la lògica de negoci (RF1-RF4) coberta amb pytest. Mínim exigible: la suite de 12-04 (uns 25 tests) en verd. Els criteris d'acceptació de sota són l'especificació d'aquests tests.
  • RNF2 — Type hints: totes les funcions públiques del paquet papyrus anotades (paràmetres i retorn), com vas aprendre a 08-01.
  • RNF3 — Errors propis: cap error de negoci no es comunica amb ValueError genèric ni amb print; sempre la jerarquia ErrorPapyrus de M7. La interfície els tradueix a codis HTTP o missatges d'usuari.
  • RNF4 — README: un README.md amb què és el projecte, com instal·lar-lo (venv + requirements.txt), com usar-lo i com executar els tests. Plantilla completa a 12-05.

Criteris d'acceptació mesurables

"Funciona" no és un criteri; això sí. Cada fila és verificable amb una acció concreta:

Requisit Criteri d'acceptació (verificable)
RF1 Donar d'alta "Faust" dues vegades produeix error (409 a l'API / missatge al form); després d'esborrar un llibre, consultar-lo retorna LlibreNoTrobatError (404).
RF2 Vendre L'Odissea a LLUIS-001 cobra 12.35 €; a la Júlia (sense soci), 13.00 €; amb codi PEPE-999, SociInvalidError.
RF3 Vendre 5 Odissees amb estoc 4 llança EstocInsuficientError i l'estoc continua sent 4; Faust + soci + PAPYRUS10 cobra 18.67 €; cupó NOEXISTEIXCupoInvalidError.
RF4 Després de vendre i reiniciar el programa, l'estoc llegit de cataleg.json reflecteix la venda; matar el procés durant un guardat no deixa un JSON corrupte.
RF5 A: els 6 endpoints responen amb els codis correctes (provat amb el test client). B: llistat, detall, venda i admin operatius (provat amb Client).
RF6 Executar l'informe sobre vendes_2026.csv imprimeix 520 unitats totals i dissabte com a millor dia (130 u), i deixa informe_2026.png a disc.
RF7 Després d'una venda rebutjada per estoc, dades/papyrus.log conté una línia WARNING amb el títol i les unitats demanades.
RNF1-4 pytest en verd; mypy (o revisió manual) sense funcions públiques sense anotar; la cerca d'except Exception genèrics sense justificar dona zero; el README permet a una altra persona arrencar el projecte sense preguntar-te res.

Les quanties surten de la fórmula de tot el curs: preu × 1.04 (IVA) × 0.95 (soci), arrodonit a 2 decimals, i el cupó s'aplica sobre aquest resultat. Verifica-ho amb els quatre llibres canònics: L'Odissea 12.50 → 13.00 / 12.35; Hamlet 9.95 → 10.35 / 9.83; El Quixot 15.90 → 16.54 / 15.71; Faust 21.00 → 21.84 / 20.75.

Abast: el que queda fora

Tan important com el què és el què no. Decidir l'abast és enginyeria; voler fer-ho tot és la manera més segura de no acabar res.

Fora de l'abast Per què On reprendre-ho
Autenticació real (usuaris, contrasenyes, sessions) Requereix seguretat seriosa (hashing, CSRF, tokens); mal feta és pitjor que absent Extensions a 12-05
Pagaments Integració amb passarel·les externes, fora del temari Extensions a 12-05
Desplegament a producció Servidors, HTTPS, dominis: un altre ofici Extensions a 12-05
Base de dades SQL a l'itinerari A JSON/CSV són suficients per al volum de Papyrus i són el que has practicat a M6 Extensions a 12-05
Front-end elaborat (JavaScript, CSS avançat) El curs és de Python; un HTML mínim és suficient Extensions a 12-05

Si en acabar et quedes amb ganes, perfecte: 12-05 ordena aquestes extensions per dificultat. Però primer es lliura l'abast acordat.

Dos itineraris

RF5 es compleix per un de dos camins. Tria segons què vulguis reforçar, no segons quin "sona millor":

Itinerari A — API Flask Itinerari B — web Django
Què construeixes API REST JSON sobre el teu paquet papyrus Aplicació web amb plantilles, forms i admin
Base del curs 10-02 i 10-03 10-04 i 10-05
Persistència Els teus repositoris JSON/CSV (RF4 íntegre) ORM de Django per al catàleg; les vendes segueixen en CSV
Esforç relatiu Menor en interfície, major en persistència (tot és teu) Major en interfície (plantilles, forms), menor en persistència (l'ORM regala molt)
Reforça Disseny d'APIs, codis HTTP, separació de capes Frameworks complets, convencions, ORM
Risc típic Oblidar validar l'entrada JSON Ficar lògica de negoci a les vistes
Tria'l si… T'estira el backend pur o el treball amb dades T'estira el desenvolupament web de producte

Els dos itineraris comparteixen el 70 % del projecte (tot el core, la persistència de vendes, l'informe i els tests de negoci). La decisió afecta només la fita H4 de la planificació.

Mapa de requisits → mòduls del curs

Res d'aquest projecte no és nou. Cada requisit apunta a mòduls on ja ho vas aprendre — aquesta taula és la teva xuleta d'"on repassar":

Requisit Què necessita Mòdul(s) on es va aprendre
RF1 catàleg dataclass Llibre, diccionaris com a índex, funcions del magatzem M5 (05-06), M4 (04-03), M3
RF2 socis Validació, SociInvalidError, constants M2, M7 (07-04), M1
RF3 vendes i cupons Condicionals, excepcions pròpies, aplicar_cupo, arrodoniment M2, M7, M3, M1 (floats)
RF4 persistència JSON, CSV, pathlib, guardat atòmic amb context manager M6, M8 (08-04)
RF5-A API Flask Rutes, JSON, codis d'estat, errorhandler M10 (10-02, 10-03)
RF5-B web Django Models, vistes, plantilles, ModelForm, admin M10 (10-04, 10-05)
RF6 informe pandas (groupby), Matplotlib (savefig) M11 (11-03, 11-04)
RF7 logging logging amb nivells i fitxer M7 (07-05)
RNF1 tests pytest, fixtures, parametrize, tmp_path M9 (09-01 a 09-03)
RNF2 type hints Anotacions com a especificació M8 (08-01)
RNF3 errors Jerarquia ErrorPapyrus M7 (07-04)
RNF4 README Entorns virtuals, pip, requirements M1 (01-06)

I M11 complet, amb la seva regressió? Reapareix a 12-05: l'informe final inclourà una recomanació a l'estil de la comanda de Sant Jordi (predicció 172, comanda de l'Anna 190 — el model recomana, la persona decideix).

Com treballar aquest mòdul

Les cinc lliçons segueixen el cicle de vida real d'un projecte: requisits (aquesta), disseny (12-02), construcció (12-03), verificació (12-04) i lliurament (12-05). Treballa amb l'editor obert: cada lliçó acaba amb fites que has de completar abans de la següent. Reutilitza el teu codi de mòduls anteriors sense vergonya — reutilitzar el que és propi és el que fan els professionals — però copia'l a un projecte nou i neteja'l en passar-lo: el projecte final mereix començar en una carpeta neta.

Errors Comuns i Consells

  • Començar a programar avui mateix. La temptació és enorme i l'error, clàssic: sense el disseny de 12-02 acabaràs reescrivint. Un dia de disseny estalvia tres dies de refactor.
  • Ampliar l'abast a mig camí ("ja que hi soc, li poso login…"). Se'n diu scope creep i mata més projectes personals que cap bug. Apunta la idea per a 12-05 i continua.
  • Triar l'itinerari B "perquè Django és més professional". Cap dels dos no és més professional; són oficis diferents. Tria pel que vulguis reforçar.
  • Tractar els criteris d'acceptació com a decoratius. Són el contracte: a 12-04 es converteixen un a un en tests. Si un criteri et sembla ambigu ara, redacta'l millor ara — és molt més barat que descobrir l'ambigüitat amb el codi escrit.
  • Saltar-se les quanties canòniques. 12.35, 9.83, 15.71, 20.75 fa tot el curs que són la veritat. Si el teu sistema dona un altre número, el bug és teu, no de la taula.

Exercicis

Aquest mòdul substitueix els exercicis de pràctica per fites de projecte: treball real sobre el teu lliurable, amb criteris de verificació.

  1. Fita 0.1 — Tria itinerari i deixa-ho per escrit. Crea la carpeta del projecte (papyrus_online/) amb un fitxer DECISIONS.md i escriu-hi 3-5 línies: quin itinerari tries i per què, en termes de què vols reforçar. Aquest fitxer creixerà durant tot el mòdul.
  2. Fita 0.2 — Auditoria de peces reutilitzables. Recorre el teu codi de M1-M11 i llista a DECISIONS.md quins fitxers reutilitzaràs (amb el seu origen) i quins faràs de zero. Mínim: revisa models.py, errors.py, cupons.py, magatzem.py, els teus tests de M9 i la teva app de M10.
  3. Fita 0.3 — Un criteri més. Redacta un criteri d'acceptació addicional per al requisit que pitjor entenguis, amb el format de la taula (acció concreta → resultat verificable). Redactar-lo t'obligarà a entendre el requisit.

Solucions

Orientatives — l'important és que existeixin i siguin concretes:

  1. Exemple vàlid: «Itinerari A. A M10, Django em va resultar més guiat i Flask em va deixar més dubtes sobre codis HTTP i validació d'entrada; vull tancar aquests dubtes. A més, l'itinerari A m'obliga a fer la persistència sencera, que és on em sento menys segur.»
  2. Reutilitzables típics: models.py (M5, afegint-hi Soci), errors.py (M7, tal qual), cupons.py (M7, tal qual), aplicar_cupo i constants de M1; de zero o molt retocats: magatzem.py (passarà a serveis + repositoris a 12-02), la interfície (es refà sobre el disseny nou), l'informe (guió nou sobre el que has après a M11).
  3. Exemple per a RF4: «Executo una venda, mato el procés, torno a arrencar: el catàleg carrega sense error i l'estoc és coherent (o la venda completa es va aplicar, o no es va aplicar res — mai a mitges).» Si el teu criteri no diu com verificar-lo, no és un criteri: és un desig.

Conclusió

Ja tens el contracte: set requisits funcionals, quatre de no funcionals, criteris d'acceptació que es poden comprovar (i que a 12-04 es convertiran en tests), un abast amb fronteres clares i dos itineraris entre els quals ja has triat. També has vist que no hi ha res de nou per aprendre: cada requisit apunta a un mòdul on ja vas viure la solució. El que és nou és l'acoblament — i l'acoblament comença pel plànol. A la propera lliçó convertirem aquests requisits en un pla: fites ordenades, arquitectura en capes, esquemes de dades i contractes de funcions escrits abans de programar. Resisteix un dia més la temptació de l'editor: primer el plànol, després els maons.

Curs de Programació en Python

Mòdul 1: Introducció a Python

Mòdul 2: Estructures de Control

Mòdul 3: Funcions i Mòduls

Mòdul 4: Estructures de Dades

Mòdul 5: Programació Orientada a Objectes

Mòdul 6: Gestió de Fitxers

Mòdul 7: Gestió d'Errors i Excepcions

Mòdul 8: Temes Avançats

Mòdul 9: Proves i Depuració

Mòdul 10: Desenvolupament Web amb Python

Mòdul 11: Ciència de Dades amb Python

Mòdul 12: Projecte Final

© Copyright 2026. Tots els drets reservats