/* POLEO FISCAL - exemple de integrare in C, intr-un singur fisier. Perechea lui `poleo_demo.py` si `poleo_demo.php`, cu ACELEASI numere de exemplu: exemplul 31 de aici este exemplul 31 de acolo. Explicatiile lungi (de ce, ce se strica daca gresesti, ce raspunde casa) stau in fisierul Python si pe https://poleo.ro/docs/api - aici sunt notele scurte, ca sa nu tinem aceeasi proza in trei locuri si sa ajunga sa se contrazica. Clientul propriu-zis este in `poleo_fiscal.c` / `poleo_fiscal.h`, langa acest fisier. gcc -std=c99 -Wall poleo_fiscal.c poleo_demo.c -lwinhttp -o poleo_demo.exe cl /W3 poleo_fiscal.c poleo_demo.c winhttp.lib /Fe:poleo_demo.exe cc -std=c99 -DPOLEO_CU_CURL poleo_fiscal.c poleo_demo.c -lcurl -o poleo_demo poleo_demo --lista ce exemple exista poleo_demo 5 ruleaza un exemplu poleo_demo 5 7 19 mai multe poleo_demo toate toate, mai putin cele periculoase poleo_demo 30 --da si cele periculoase (raport Z), cu acceptul tau CONFIGURARE - trei valori, din variabile de mediu: set POLEO_URL=http://127.0.0.1:9111 adresa statiei set POLEO_TOKEN=... Setari -> API -> "Copiaza tokenul" set POLEO_CASA=DB9999999999 NUI-ul casei (exemplul 2 ti-l arata) */ #include #include #include #include #include "poleo_fiscal.h" static poleo_t P; /* == afisare =================================================================================== */ static void titlu(const char *text) { int i; printf("\n"); for (i = 0; i < 74; i++) putchar('-'); printf("\n%s\n", text); for (i = 0; i < 74; i++) putchar('-'); printf("\n"); } static void nota(const char *text) { printf(" %s\n", text); } /* arata raspunsul si il elibereaza; un refuz se tipareste, nu opreste demonstratia */ static void arata(const char *eticheta, poleo_raspuns_t *r) { printf("\n%s:\n", eticheta); if (r->cod == 0) { printf(" %s\n", r->mesaj); } else if (!r->ok) { printf(" HTTP %d (%s): %s\n", r->cod, r->cod_eroare[0] ? r->cod_eroare : "-", r->mesaj); /* 501 + unsupported = DEFINITIV. Nu se reincearca, nici acum nici maine. */ if (poleo_nesuportat(r)) { printf(" NESUPORTAT de aparatul asta. Solutia este alt terminal, alt model,\n"); printf(" sau alt contract cu banca - nu o reincercare.\n"); } } else { printf("%s\n", r->corp ? r->corp : ""); } poleo_elibereaza(r); } /* Cheie de operatiune pentru exemple. ATENTIE, aici este o ALTA cheie la fiecare rulare (are ora in ea) - altfel al doilea rulaj al demonstratiei n-ar mai tipari nimic, ti-ar intoarce rezultatul primului si ai crede ca s-a stricat ceva. IN PROGRAMUL TAU cheia trebuie sa fie STABILA pentru aceeasi vanzare, ca reincercarea sa nu tipareasca al doilea bon.*/ static const char *cheie_demo(const char *nume) { static char t[128]; sprintf(t, "demo-%s-%ld", nume, (long) time(NULL)); return t; } /* id-ul ultimului bon TIPARIT din evidenta - returul si declaratia lucreaza pe el */ static int ultimul_bon(char *afara, size_t n) { poleo_raspuns_t r; int gasit = 0; afara[0] = 0; if (poleo_bonuri(&P, 10, &r)) { /* cititorul din client ia PRIMUL camp cu numele cerut, adica primul bon din lista */ gasit = poleo_text(&r, "id", afara, n); } poleo_elibereaza(&r); return gasit && afara[0]; } /* == 1-4: legatura si ce stie statia =========================================================== */ static void ex1_conectare(void) { poleo_raspuns_t r; titlu("1. Conectarea la API"); poleo_sanatate(&P, &r); arata("GET /health (singura cale care nu cere token)", &r); poleo_metode(&P, &r); arata("GET /methods", &r); nota("Cere /methods la pornirea integrarii tale, nu presupune. O statie mai veche poate sa nu"); nota("aiba ultimele metode, iar asa afli din cod, nu dintr-o eroare la client."); } static void ex2_casele(void) { poleo_raspuns_t r; titlu("2. Ce case sunt configurate (si de unde iei NUI-ul)"); poleo_casele(&P, &r); arata("GET /cases", &r); nota("NUI-ul este identificatorul casei si nu se schimba pe toata durata vietii aparatului."); nota("Denumirea si id-ul din baza se pot schimba; NUI-ul, nu. Trimite-l de la inceput."); } static void ex3_stare(void) { poleo_raspuns_t r; titlu("3. Starea casei, intrebata acum"); if (!P.casa[0]) printf("(pune POLEO_CASA ca sa interoghezi o casa anume)\n"); poleo_stare(&P, NULL, &r); arata("GET /cases//status", &r); nota("Vorbeste chiar cu aparatul, deci intreaba la intervale rezonabile, nu in bucla."); nota("Starea monitorizarii si ziua fiscala vin din /problems, nu de aici."); } static void ex4_config(void) { poleo_raspuns_t r; titlu("4. Cotele de TVA si metodele de incasare, citite din casa"); poleo_config(&P, NULL, &r); arata("GET /cases//config", &r); nota("Astea sunt adevarul. Nu presupune ca 21% este mereu grupa A sau ca 0 = NUMERAR,"); nota("pentru ca vei altera datele fiscal-contabile."); } /* == 5-18: bonuri ============================================================================== */ static void ex5_bon_numerar(void) { poleo_raspuns_t r; poleo_bon_t *b = poleo_bon_nou(); titlu("5. Bon fiscal platit cu NUMERAR"); poleo_bon_articol(b, "APA PLATA 0.5L", 3.50, 2, "buc", 21); poleo_bon_plata(b, "cash", 7.00); poleo_tipareste(&P, b, cheie_demo("numerar"), &r); arata("POST /receipts", &r); poleo_bon_elibereaza(b); nota("`receipt_no` este numarul bonului tiparit. Pune-l in evidenta ta - este legatura dintre"); nota("vanzarea din programul tau si hartia pe care o are clientul."); } static void ex6_citeste_bonul(void) { poleo_raspuns_t r; char id[64]; titlu("6. Citirea raspunsului: ultimul bon din evidenta"); poleo_bonuri(&P, 1, &r); arata("GET /receipts?limit=1", &r); if (ultimul_bon(id, sizeof(id))) { poleo_bonul(&P, id, &r); arata("GET /receipts/ (cu liniile lui)", &r); } nota("Lista este pentru verificare ulterioara: reconciliere de sfarsit de zi, sau aflarea a ce"); nota("s-a intamplat cu un bon intrat in coada cat timp casa era deconectata."); } static void ex7_bon_card(void) { poleo_raspuns_t r; poleo_bon_t *b = poleo_bon_nou(); titlu("7. Bon fiscal platit cu CARDUL"); poleo_bon_articol(b, "CAFEA LA FILTRU", 12.00, 1, "buc", 21); poleo_bon_plata(b, "card", 12.00); poleo_tipareste(&P, b, cheie_demo("card"), &r); arata("POST /receipts", &r); poleo_bon_elibereaza(b); nota("Asta TIPARESTE bonul; nu cere banii de pe card. Pentru terminalul bancar este /pos."); } static void ex8_plati_card(void) { poleo_raspuns_t r; titlu("8. Citirea raspunsului pentru platile cu cardul"); poleo_plati_card(&P, 5, &r); arata("GET /card-payments?limit=5", &r); nota("Pastreaza `auth` si `rrn` - cu ele reconciliezi cu extrasul bancii. Plata INCERTA este"); nota("cazul care conteaza: nu o relua automat, cardul poate fi deja debitat."); } static void ex9_bon_adaos(void) { poleo_raspuns_t r; poleo_bon_t *b = poleo_bon_nou(); titlu("9. Bon cu ADAOS (majorare)"); poleo_bon_articol_ajustat(b, "LIVRARE URGENTA", 20.00, 1, "buc", 21, "sur_pct", 15); poleo_bon_plata(b, "cash", 23.00); poleo_tipareste(&P, b, cheie_demo("adaos"), &r); arata("POST /receipts", &r); poleo_bon_elibereaza(b); nota("sur_val = majorare in lei, sur_pct = procent. Suma platilor este totalul DUPA ajustare:"); nota("20 + 15% = 23,00."); } static void ex10_bon_reducere(void) { poleo_raspuns_t r; poleo_bon_t *b = poleo_bon_nou(); titlu("10. Bon cu REDUCERE"); poleo_bon_articol_ajustat(b, "VIN ROSU 0.75L", 45.00, 1, "buc", 21, "dis_pct", 10); poleo_bon_articol(b, "PAINE DE CASA", 8.00, 1, "buc", 11); poleo_bon_plata(b, "cash", 48.50); poleo_tipareste(&P, b, cheie_demo("reducere"), &r); arata("POST /receipts", &r); poleo_bon_elibereaza(b); nota("Individualizeaza EXPRES produsul redus, fara exceptie. Are implicatii nu doar"); nota("fiscal-contabile, ci si juridice: clientul trebuie sa vada din ce s-a compus suma."); } static void ex11_plati_multiple(void) { poleo_raspuns_t r; poleo_bon_t *b = poleo_bon_nou(); titlu("11. Bon cu DOUA metode de plata"); poleo_bon_articol(b, "MENIU ZILEI", 40.00, 1, "buc", 11); poleo_bon_plata(b, "cash", 15.00); poleo_bon_plata(b, "card", 25.00); poleo_tipareste(&P, b, cheie_demo("mixt"), &r); arata("POST /receipts", &r); poleo_bon_elibereaza(b); nota("Suma platilor trebuie sa dea exact totalul bonului. Casa refuza altfel, si bine face."); } static void ex12_cote_multiple(void) { poleo_raspuns_t r; poleo_bon_t *b = poleo_bon_nou(); titlu("12. Bon cu mai multe cote de TVA"); poleo_bon_articol(b, "PAINE", 5.00, 1, "buc", 11); poleo_bon_articol(b, "DETERGENT", 24.00, 1, "buc", 21); poleo_bon_articol(b, "AMBALAJ SGR", 0.50, 1, "buc", 0); poleo_bon_plata(b, "cash", 29.50); poleo_tipareste(&P, b, cheie_demo("cote"), &r); arata("POST /receipts", &r); poleo_bon_elibereaza(b); nota("Garantia SGR merge pe cota 0 - nu este o vanzare, este o garantie returnabila."); } static void ex13_bon_complet(void) { poleo_raspuns_t r; poleo_bon_t *b = poleo_bon_nou(); titlu("13. Bon complet: mai multe articole, ajustari, doua plati"); poleo_bon_articol(b, "PIZZA CAPRICCIOSA", 38.00, 2, "buc", 11); poleo_bon_articol(b, "APA MINERALA 0.5L", 6.00, 2, "buc", 21); poleo_bon_articol_ajustat(b, "TAXA LIVRARE", 12.00, 1, "buc", 21, "dis_val", 2.00); poleo_bon_plata(b, "card", 80.00); poleo_bon_plata(b, "cash", 8.00); poleo_tipareste(&P, b, cheie_demo("complet"), &r); arata("POST /receipts", &r); poleo_bon_elibereaza(b); nota("Verifica intotdeauna ca totalul platilor este cel calculat de tine DUPA ajustari -"); nota("nu lasa casa sa te corecteze, ca nu o face."); } static void ex14_storno(void) { poleo_raspuns_t r; poleo_bon_t *b = poleo_bon_nou(); titlu("14. Linie de STORNO in bonul deschis"); poleo_bon_articol(b, "BERE 0.5L", 9.00, 2, "buc", 21); poleo_bon_storno(b, "BERE 0.5L", 9.00, 1, 21); poleo_bon_plata(b, "cash", 9.00); poleo_tipareste(&P, b, cheie_demo("storno"), &r); arata("POST /receipts", &r); poleo_bon_elibereaza(b); nota("Stornarea se face IN bonul care inca nu s-a inchis. Dupa ce bonul a iesit, nu mai este"); nota("storno - este retur (exemplul 42)."); } static void ex15_stil_coduri(void) { poleo_raspuns_t r; poleo_bon_t *b = poleo_bon_nou(); titlu("15. Articole trimise pe COD, nu pe denumire"); poleo_bon_articol_cod(b, "1024", 3, 21); poleo_bon_plata(b, "cash", 30.00); poleo_tipareste(&P, b, cheie_demo("cod"), &r); arata("POST /receipts", &r); poleo_bon_elibereaza(b); nota("Merge doar daca articolul EXISTA in nomenclatorul casei, cu pretul programat acolo."); } static void ex16_copie(void) { poleo_raspuns_t r; titlu("16. Copia ultimului bon"); poleo_copie(&P, cheie_demo("copie"), &r); arata("POST /copy", &r); nota("Copia se tipareste cu mentiunea de duplicat. Nu este un al doilea bon fiscal."); } static void ex17_void(void) { poleo_raspuns_t r; titlu("17. Anularea bonului DESCHIS"); poleo_anuleaza_bon_deschis(&P, cheie_demo("void"), &r); arata("POST /void", &r); nota("Doar bonul nefinalizat. Functioneaza si cu licenta expirata - este una dintre cele doua"); nota("supape ale programului (cealalta este sertarul)."); } static void ex18_probleme(void) { poleo_raspuns_t r; titlu("18. Ce nu este in regula acum"); poleo_probleme(&P, &r); arata("GET /problems", &r); nota("Asta pui in bara de stare: monitorizare, ziua fiscala si de cate ore este deschisa,"); nota("hartie, legatura. Nu starea casei - aia vorbeste cu aparatul de fiecare data."); } /* == 19-30: rapoarte, numerar, ANAF, jurnal ==================================================== */ static void ex19_raport_x(void) { poleo_raspuns_t r; titlu("19. Raport X (citire, fara sa inchida ziua)"); poleo_raport(&P, "X", NULL, cheie_demo("x"), &r); arata("POST /reports {kind: X}", &r); nota("X este singura \"proba\" acceptabila daca vrei sa verifici ca ai legatura cu aparatul."); } static void ex20_nomenclator(void) { poleo_raspuns_t r; const char *feluri[] = { "nomenclator", "plu", "departments" }; size_t i; titlu("20. Raportul de nomenclator"); for (i = 0; i < sizeof(feluri) / sizeof(feluri[0]); i++) { int ok = poleo_raport(&P, feluri[i], NULL, cheie_demo("nom"), &r); arata("POST /reports", &r); if (ok) break; } nota("Nu orice casa are toate felurile. Cere /methods (exemplul 1) ca sa stii ce accepta a ta."); } static void ex21_depunere(void) { poleo_raspuns_t r; titlu("21. Depunere de numerar in sertar"); poleo_numerar(&P, "in", 200, "Fond de rulaj", cheie_demo("dep"), &r); arata("POST /cash {kind: in}", &r); } static void ex22_retragere(void) { poleo_raspuns_t r; titlu("22. Retragere de numerar din sertar"); poleo_numerar(&P, "out", 150, "Ridicare incasari", cheie_demo("retr"), &r); arata("POST /cash {kind: out}", &r); nota("Se tipareste pe casa. Deci: cheie de operatiune, ca la bonuri."); } static void ex23_sertar(void) { poleo_raspuns_t r; titlu("23. Soldul de sertar"); poleo_sertar(&P, &r); arata("GET /drawer", &r); } static void ex24_totaluri(void) { poleo_raspuns_t r; titlu("24. Totalurile zilei si cotele"); poleo_totaluri(&P, &r); arata("GET /totals", &r); poleo_cote(&P, &r); arata("GET /vat", &r); nota("Ziua fiscala incepe la ultimul raport Z, nu la ora 00:00. Doua zile calendaristice pot"); nota("sta in aceeasi zi fiscala, si invers."); } static void ex25_anaf_stare(void) { poleo_raspuns_t r; titlu("25. Starea raportarii ANAF"); poleo_anaf(&P, &r); arata("GET /anaf", &r); } static void ex26_raport_periodic(void) { poleo_raspuns_t r; titlu("26. Raport periodic din memoria fiscala"); poleo_raport(&P, "periodic", "\"from\":\"01-08-2026\",\"to\":\"31-08-2026\",\"detailed\":false", cheie_demo("periodic"), &r); arata("POST /reports {kind: periodic}", &r); nota("Datele se dau zi-luna-an, NU in ISO. Poate tipari zeci de secunde - de aceea"); nota("POLEO_TIMEOUT_LUNG, nu cele 5 secunde obisnuite intr-un client HTTP."); } static void ex27_export_je(void) { poleo_raspuns_t r; titlu("27. Export de jurnal electronic pentru ANAF"); poleo_export_je(&P, "01-08-2026", "31-08-2026", cheie_demo("je"), &r); arata("POST /anaf", &r); } static void ex28_lista_je(void) { poleo_raspuns_t r; char id[64]; titlu("28. Salvarile de jurnal electronic"); poleo_je(&P, 3, &r); arata("GET /je?limit=3", &r); if (poleo_je(&P, 1, &r) && poleo_text(&r, "id", id, sizeof(id))) { poleo_elibereaza(&r); poleo_je_salvare(&P, id, &r); arata("GET /je/ (fisierele salvarii)", &r); } else { poleo_elibereaza(&r); } } static void ex29_descarca_je(void) { poleo_raspuns_t r; char id[64], nume[256]; titlu("29. Descarcarea unui fisier de jurnal (raspuns BINAR)"); if (!poleo_je(&P, 1, &r) || !poleo_text(&r, "id", id, sizeof(id))) { printf("(nicio salvare de jurnal - ruleaza intai exemplul 27)\n"); poleo_elibereaza(&r); return; } poleo_elibereaza(&r); if (!poleo_je_salvare(&P, id, &r) || !poleo_text(&r, "name", nume, sizeof(nume))) { printf("(salvarea nu are fisiere)\n"); poleo_elibereaza(&r); return; } poleo_elibereaza(&r); if (poleo_je_fisier(&P, id, nume, &r)) { FILE *f = fopen(nume, "wb"); if (f) { fwrite(r.corp, 1, r.corp_lung, f); fclose(f); printf("%s: %lu octeti, scris pe disc\n", nume, (unsigned long) r.corp_lung); } } poleo_elibereaza(&r); nota("Raspunsul este BINAR, nu JSON. Foloseste `corp_lung`, NU strlen: un fisier de jurnal"); nota("poate contine octetul zero, iar strlen l-ar taia acolo."); } static void ex30_raport_z(void) { poleo_raspuns_t r; char cheie[64]; time_t acum = time(NULL); struct tm *t = localtime(&acum); titlu("30. Raport Z (INCHIDE ZIUA FISCALA)"); strftime(cheie, sizeof(cheie), "z-%Y-%m-%d", t); poleo_raport(&P, "Z", NULL, cheie, &r); arata("POST /reports {kind: Z}", &r); nota("Cheia este ziua, nu ora: doua apasari in aceeasi zi nu dau doua rapoarte Z."); nota("Z-ul pune toate valorile pe 0. Nu-l chema din cron fara sa stii ce faci."); } /* == 31-32: idempotenta si erorile ============================================================= */ static void ex31_idempotenta(void) { poleo_raspuns_t r; poleo_bon_t *b; const char *cheie = cheie_demo("idem"); char pastrata[128]; titlu("31. Cheia de operatiune, pe viu"); strcpy(pastrata, cheie); /* cheie_demo scrie intr-un buffer static; o pastram */ b = poleo_bon_nou(); poleo_bon_articol(b, "TEST IDEMPOTENTA", 1.00, 1, "buc", 21); poleo_bon_plata(b, "cash", 1.00); poleo_tipareste(&P, b, pastrata, &r); arata("prima trimitere", &r); poleo_tipareste(&P, b, pastrata, &r); arata("A DOUA trimitere, cu ACEEASI cheie", &r); poleo_bon_elibereaza(b); nota("Al doilea raspuns este acelasi ca primul, si NU a iesit al doilea bon. Asta te salveaza"); nota("cand reteaua cade dupa ce bonul a iesit si programul tau reincearca."); } static void ex32_erori(void) { poleo_raspuns_t r; poleo_bon_t *b; titlu("32. Cum arata refuzurile, si pe ce te ramifici"); b = poleo_bon_nou(); poleo_bon_plata(b, "cash", 1.00); /* bon fara articole */ poleo_tipareste(&P, b, cheie_demo("gol"), &r); arata("bon fara articole", &r); poleo_bon_elibereaza(b); b = poleo_bon_nou(); poleo_bon_articol(b, "X", 10.00, 1, "buc", 21); poleo_bon_plata(b, "cash", 5.00); /* plata nu acopera bonul */ poleo_tipareste(&P, b, cheie_demo("scurt"), &r); arata("plata care nu acopera bonul", &r); poleo_bon_elibereaza(b); poleo_raport(&P, "nu-exista-asa-ceva", NULL, cheie_demo("rap"), &r); arata("raport care nu exista", &r); nota("Ramifica-te pe `cod_eroare`, NU pe mesaj: codul este stabil, mesajul este pentru om si"); nota("se poate schimba fara sa strice integrarea ta."); } /* == 33-41: sertar si terminalul de card ======================================================= */ static void ex33_sertar_deschide(void) { poleo_raspuns_t r; titlu("33. Deschiderea sertarului"); poleo_deschide_sertar(&P, cheie_demo("sertar"), &r); arata("POST /drawer", &r); nota("Necesita sertar legat electric la casa. Unele case nu-l pot gestiona, desi au port."); } static void ex34_pos_card(void) { poleo_raspuns_t r; titlu("34. Plata la terminalul de card (POS bancar)"); poleo_pos(&P, 12.00, cheie_demo("pos"), &r); arata("POST /pos", &r); nota("Asta CERE BANII de pe card; nu tipareste bonul. Intai /pos, si doar daca terminalul a"); nota("aprobat, /receipts cu plata pe card. Programul nu vede niciodata PAN, CVV sau PIN."); } static void ex35_terminale(void) { poleo_raspuns_t r; titlu("35. Terminalele de card configurate"); poleo_terminale(&P, &r); arata("GET /terminals", &r); nota("Citeste `can` INAINTE sa promiti ceva clientului - se citeste din driver, nu de pe fir."); nota("Ce este `false` acolo nu se reincearca niciodata."); } static void ex36_licenta(void) { poleo_raspuns_t r; titlu("36. Licenta fiecarei case"); poleo_licenta(&P, &r); arata("GET /license", &r); nota("O licenta expirata opreste bonurile, rapoartele si miscarile de numerar. Afla inainte,"); nota("nu in dimineata in care casa refuza."); } static void ex37_statie(void) { poleo_raspuns_t r; titlu("37. Amprenta statiei, locatia si casele ei"); poleo_statie(&P, &r); arata("GET /station", &r); nota("AMPRENTA este numele sub care te cunosc partenerii. Nu se schimba nici la actualizare,"); nota("nici daca schimbi portul, IP-ul sau casa."); } static void ex38_restul_evidentei(void) { poleo_raspuns_t r; char id[64]; titlu("38. Restul evidentei: numerar, rapoarte tiparite, declaratii, posta"); poleo_miscari_numerar(&P, 3, &r); arata("GET /cash?limit=3 (miscarile de numerar)", &r); poleo_rapoarte(&P, 3, &r); arata("GET /reports?limit=3 (rapoartele tiparite)", &r); poleo_declaratii(&P, 3, &r); arata("GET /declarations?limit=3 (declaratii de bon gresit)", &r); poleo_posta(&P, 3, &r); arata("GET /emails?limit=3 (posta de iesire)", &r); if (poleo_declaratii(&P, 1, &r) && poleo_text(&r, "id", id, sizeof(id))) { poleo_elibereaza(&r); if (poleo_declaratie_fisier(&P, id, &r)) { char nume[128]; FILE *f; sprintf(nume, "declaratie-%s.pdf", id); f = fopen(nume, "wb"); if (f) { fwrite(r.corp, 1, r.corp_lung, f); fclose(f); printf("PDF-ul declaratiei: %lu octeti -> %s\n", (unsigned long) r.corp_lung, nume); } } } else { printf("(nicio declaratie de bon gresit - normal pe o casa fara incidente)\n"); } poleo_elibereaza(&r); nota("Lista completa si mereu la zi o da chiar statia, la /methods."); } static void ex39_retur_card(void) { poleo_raspuns_t r; titlu("39. Retur pe card"); poleo_pos_retur(&P, 25.00, cheie_demo("retur"), &r); arata("POST /pos/refund", &r); nota("Scoate bani REALI din contul comerciantului. Verifica `can.refund` la /terminals INAINTE."); nota("Altceva decat exemplul 42: acolo este returul PE BON, aici returul PE TERMINAL."); } static void ex40_anulare_card(void) { poleo_raspuns_t r; titlu("40. Anularea unei plati cu cardul"); poleo_pos_anulare(&P, "000123", 25.00, cheie_demo("anulare"), &r); arata("POST /pos/void", &r); nota("Are nevoie de STAN SI de suma exacta, tocmai ca sa nu anulezi alta tranzactie."); nota("Pastreaza STAN-ul la fiecare plata, altfel nu mai ai cu ce anula."); } static void ex41_settlement(void) { poleo_raspuns_t r; titlu("41. Inchiderea de zi a terminalului (settlement)"); poleo_pos_inchidere_zi(&P, cheie_demo("settlement"), &r); arata("POST /pos/settlement", &r); nota("NU are legatura cu raportul Z al casei - sunt doua zile diferite. Nu o facem noi"); nota("automat: are efect asupra banilor, deci o cere omul."); } /* == 42-45: returul pe bon emis, documentele, firma, setarile ================================== */ static void ex42_retur(void) { poleo_raspuns_t r; char id[64]; titlu("42. Retur pe un bon deja emis"); if (!ultimul_bon(id, sizeof(id))) { printf("(niciun bon in evidenta - ruleaza intai exemplul 5)\n"); } else { poleo_retur(&P, id, "produs defect, adus inapoi de client", "demo", cheie_demo("retur-bon"), &r); arata("POST /returns", &r); } poleo_retururi(&P, 3, &r); arata("GET /returns?limit=3", &r); nota("NU se tipareste bon de storno: bonul initial ramane valabil. Ce iese este retragerea de"); nota("numerar si procesul-verbal. Acelasi bon nu poate fi returnat peste suma lui."); } static void ex43_declaratie(void) { poleo_raspuns_t r; char id[64], motiv[64]; titlu("43. Declaratia de bon gresit"); poleo_motive_declaratie(&P, &r); arata("GET /declaration-reasons", &r); motiv[0] = 0; if (poleo_motive_declaratie(&P, &r)) poleo_text(&r, "key", motiv, sizeof(motiv)); poleo_elibereaza(&r); if (motiv[0] && ultimul_bon(id, sizeof(id))) { poleo_declaratie(&P, id, motiv, "demo", cheie_demo("decl"), &r); arata("POST /declarations", &r); } nota("Motivele se iau din /declaration-reasons, nu se inventeaza. PDF-ul se descarca separat,"); nota("ca raspuns binar (exemplul 38)."); } static void ex44_firma(void) { poleo_raspuns_t r; titlu("44. Datele firmei, asa cum le stie statia"); poleo_firma(&P, &r); arata("GET /company", &r); nota("Sunt datele cu care se scriu documentele. Se configureaza PE CASA, nu global."); } static void ex45_setari(void) { poleo_raspuns_t r; titlu("45. Setarile statiei: citire si scriere"); poleo_setari(&P, &r); arata("GET /settings", &r); nota("Parolele NU ies niciodata la citire: vin cu value null si secret true."); poleo_scrie_setari(&P, "{\"bon.sertar_mereu\":false,\"api.port\":\"1\"}", &r); arata("POST /settings (una buna si una refuzata)", &r); nota("Tabul API in intregime este blocat DINADINS: API-ul nu isi poate schimba propriile"); nota("conditii de existenta. Omul il porneste si il accepta din aplicatie, si abia dupa aceea"); nota("este autorizat. Restul refuzurilor vin cu motiv, unul cate unul."); } /* == catalogul si rularea ====================================================================== */ typedef struct { int nr; const char *nume; void (*ruleaza)(void); int periculos; /* lasa urma pe care nu o poti sterge: inchide ziua, misca bani reali */ } exemplu_t; static const exemplu_t EXEMPLE[] = { { 1, "Conectarea la API", ex1_conectare, 0 }, { 2, "Casele configurate", ex2_casele, 0 }, { 3, "Starea casei", ex3_stare, 0 }, { 4, "Cotele de TVA si incasarile", ex4_config, 0 }, { 5, "Bon platit cu numerar", ex5_bon_numerar, 0 }, { 6, "Citirea unui bon din evidenta", ex6_citeste_bonul, 0 }, { 7, "Bon platit cu cardul", ex7_bon_card, 0 }, { 8, "Platile cu cardul", ex8_plati_card, 0 }, { 9, "Bon cu adaos", ex9_bon_adaos, 0 }, { 10, "Bon cu reducere", ex10_bon_reducere, 0 }, { 11, "Doua metode de plata", ex11_plati_multiple, 0 }, { 12, "Mai multe cote de TVA", ex12_cote_multiple, 0 }, { 13, "Bon complet", ex13_bon_complet, 0 }, { 14, "Storno in bonul deschis", ex14_storno, 0 }, { 15, "Articole pe cod", ex15_stil_coduri, 0 }, { 16, "Copia ultimului bon", ex16_copie, 0 }, { 17, "Anularea bonului deschis", ex17_void, 0 }, { 18, "Ce nu este in regula acum", ex18_probleme, 0 }, { 19, "Raport X", ex19_raport_x, 0 }, { 20, "Raport de nomenclator", ex20_nomenclator, 0 }, { 21, "Depunere de numerar", ex21_depunere, 0 }, { 22, "Retragere de numerar", ex22_retragere, 0 }, { 23, "Soldul de sertar", ex23_sertar, 0 }, { 24, "Totalurile zilei", ex24_totaluri, 0 }, { 25, "Starea ANAF", ex25_anaf_stare, 0 }, { 26, "Raport periodic", ex26_raport_periodic, 0 }, { 27, "Export de jurnal electronic", ex27_export_je, 0 }, { 28, "Salvarile de jurnal", ex28_lista_je, 0 }, { 29, "Descarcarea unui fisier de jurnal", ex29_descarca_je, 0 }, { 30, "Raport Z (INCHIDE ZIUA)", ex30_raport_z, 1 }, { 31, "Cheia de operatiune, pe viu", ex31_idempotenta, 0 }, { 32, "Cum arata refuzurile", ex32_erori, 0 }, { 33, "Deschiderea sertarului", ex33_sertar_deschide, 0 }, { 34, "Plata la terminalul de card", ex34_pos_card, 0 }, { 35, "Terminalele configurate", ex35_terminale, 0 }, { 36, "Licenta caselor", ex36_licenta, 0 }, { 37, "Amprenta statiei", ex37_statie, 0 }, { 38, "Restul evidentei", ex38_restul_evidentei, 0 }, { 39, "Retur pe card", ex39_retur_card, 1 }, { 40, "Anularea unei plati cu cardul", ex40_anulare_card, 1 }, { 41, "Inchiderea de zi a terminalului", ex41_settlement, 1 }, { 42, "Retur pe un bon emis", ex42_retur, 1 }, { 43, "Declaratia de bon gresit", ex43_declaratie, 0 }, { 44, "Datele firmei", ex44_firma, 0 }, { 45, "Setarile statiei", ex45_setari, 0 } }; static const size_t CATE = sizeof(EXEMPLE) / sizeof(EXEMPLE[0]); static void lista_exemple(void) { size_t i; printf("\nExemple disponibile:\n"); for (i = 0; i < CATE; i++) { printf("%3d. %-42s %s\n", EXEMPLE[i].nr, EXEMPLE[i].nume, EXEMPLE[i].periculos ? " [periculos - cere --da]" : ""); } printf("\nPericulos = lasa urma pe care nu o poti sterge: inchide ziua fiscala, misca bani reali.\n"); } static void ruleaza_nr(int nr, int da) { size_t i; for (i = 0; i < CATE; i++) { if (EXEMPLE[i].nr != nr) continue; if (EXEMPLE[i].periculos && !da) { printf("%3d. %-42s SARIT (periculos; adauga --da)\n", nr, EXEMPLE[i].nume); return; } EXEMPLE[i].ruleaza(); return; } printf("Nu exista exemplul %d. Ruleaza --lista.\n", nr); } int main(int argc, char **argv) { int i, da = 0, ceva = 0; poleo_din_mediu(&P); for (i = 1; i < argc; i++) { if (strcmp(argv[i], "--da") == 0) da = 1; } for (i = 1; i < argc; i++) { if (strcmp(argv[i], "--da") == 0) continue; if (strcmp(argv[i], "--lista") == 0) { lista_exemple(); return 0; } if (strcmp(argv[i], "toate") == 0) { size_t j; for (j = 0; j < CATE; j++) ruleaza_nr(EXEMPLE[j].nr, da); ceva = 1; continue; } ruleaza_nr(atoi(argv[i]), da); ceva = 1; } if (!ceva) lista_exemple(); return 0; }