From cfae2d1f1d8a4a518258f518322674636e8a51b7 Mon Sep 17 00:00:00 2001 From: antooinerobin Date: Mon, 30 Oct 2023 12:35:14 +0100 Subject: [PATCH] add factures service --- choruspro.go | 21 ++ choruspro_test.go | 6 + date.go | 15 + factures.go | 64 +++++ factures_consultations.go | 262 +++++++++++++++++ factures_consultations_test.go | 446 +++++++++++++++++++++++++++++ factures_depots.go | 182 ++++++++++++ factures_depots_test.go | 148 ++++++++++ factures_misc.go | 37 +++ factures_misc_test.go | 48 ++++ factures_recherches.go | 254 ++++++++++++++++ factures_recherches_test.go | 267 +++++++++++++++++ factures_traitements.go | 41 +++ factures_traitements_test.go | 54 ++++ pagination.go | 44 ++- transverses.go | 7 + transverses_pieces_jointes.go | 10 +- transverses_pieces_jointes_test.go | 2 +- transverses_structures.go | 10 +- transverses_structures_test.go | 2 +- 20 files changed, 1899 insertions(+), 21 deletions(-) create mode 100644 date.go create mode 100644 factures.go create mode 100644 factures_consultations.go create mode 100644 factures_consultations_test.go create mode 100644 factures_depots.go create mode 100644 factures_depots_test.go create mode 100644 factures_misc.go create mode 100644 factures_misc_test.go create mode 100644 factures_recherches.go create mode 100644 factures_recherches_test.go create mode 100644 factures_traitements.go create mode 100644 factures_traitements_test.go diff --git a/choruspro.go b/choruspro.go index 867bee9..8ee4cf4 100644 --- a/choruspro.go +++ b/choruspro.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "io" + "log" "net/http" "net/url" "strings" @@ -66,6 +67,7 @@ type Client struct { // Services Transverses *TransversesService + Factures *FacturesService } type service struct { @@ -103,6 +105,7 @@ func (c *Client) initialize() { c.BaseUrl, _ = url.Parse(defaultBaseURL) c.AuthUrl, _ = url.Parse(defaultAuthURL) c.Transverses = (*TransversesService)(&c.common) + c.Factures = (*FacturesService)(&c.common) } func (c *Client) newRequest(ctx context.Context, method, url string, body interface{}) (*http.Request, error) { @@ -161,6 +164,8 @@ func (c *Client) doRequest(ctx context.Context, req *http.Request, obj interface } data, err := io.ReadAll(res.Body) + // Print + log.Println(string(data)) if err != nil { return nil } @@ -215,3 +220,19 @@ func getOAuthToken(clientId, clientSecret string, authUrl *url.URL) (*oauth2.Tok return tok, nil } + +// Bool is a helper routine that allocates a new bool value +// to store v and returns a pointer to it. +func Bool(v bool) *bool { return &v } + +// Int is a helper routine that allocates a new int value +// to store v and returns a pointer to it. +func Int(v int) *int { return &v } + +// Int64 is a helper routine that allocates a new int64 value +// to store v and returns a pointer to it. +func Int64(v int64) *int64 { return &v } + +// String is a helper routine that allocates a new string value +// to store v and returns a pointer to it. +func String(v string) *string { return &v } diff --git a/choruspro_test.go b/choruspro_test.go index 14befe6..ab3da15 100644 --- a/choruspro_test.go +++ b/choruspro_test.go @@ -18,6 +18,12 @@ const ( baseAuthPath = "/api/oauth/token" ) +var ( + defaultDate = time.Date(2023, 01, 01, 0, 0, 0, 0, time.UTC) + defaultDateStr = `"2023-01-01"` + defaultDateTimeStr = `"2023-01-01T00:00:00Z"` +) + func setup() (client *Client, mux *http.ServeMux, teardown func()) { client, mux, teardown = bareSetup() diff --git a/date.go b/date.go new file mode 100644 index 0000000..a010abf --- /dev/null +++ b/date.go @@ -0,0 +1,15 @@ +package choruspro + +import ( + "time" +) + +type Date struct { + time.Time +} + +func (t *Date) UnmarshalJSON(data []byte) error { + var err error + t.Time, err = time.Parse("\"2006-01-02\"", string(data)) + return err +} diff --git a/factures.go b/factures.go new file mode 100644 index 0000000..8771555 --- /dev/null +++ b/factures.go @@ -0,0 +1,64 @@ +package choruspro + +// FacturesService gère les appels à l'API Facture +// API docs : https://developer.aife.economie.gouv.fr/api-catalog-sandbox?filter=Factures +type FacturesService service + +type ActionFacture string + +const ( + ActionFactureRefus ActionFacture = "REFUS" + ActionFactureValidation ActionFacture = "VALIDATION" + ActionFactureMiseEnPaiement ActionFacture = "MISE_EN_PAIEMENT" + ActionFactureMiseEnRecyclage ActionFacture = "MISE_EN_RECYCLAGE" + ActionFactureSuspension ActionFacture = "SUSPENSION" + ActionFactureRejet ActionFacture = "REJET" +) + +type CadreFac string + +const ( + CodeFacA1 CadreFac = "A1_FACTURE_FOURNISSEUR" + CodeFacA2 CadreFac = "A2_FACTURE_FOURNISSEUR_DEJA_PAYEE" + CodeFacA3 CadreFac = "A3_MEMOIRE_JUSTICE" + CodeFacA4 CadreFac = "A4_PROJET_DECOMPTE_MENSUEL_FOURNISSEUR" + CodeFacA5 CadreFac = "A5_ETAT_ACOMPTE_FOURNISSEUR" + CodeFacA6 CadreFac = "A6_ETAT_ACOMPTE_VALIDE_FOURNISSEUR" + CodeFacA7 CadreFac = "A7_PROJET_DECOMPTE_FINAL_FOURNISSEUR" + CodeFacA8 CadreFac = "A8_DECOMPTE_GENERAL_DEFINITIF_FOURNISSEUR" + CodeFacA9 CadreFac = "A9_FACTURE_SOUSTRAITANT" + CodeFacA10 CadreFac = "A10_PROJET_DECOMPTE_MENSUEL_SOUSTRAITANT" + CodeFacA11 CadreFac = "A11_PROJET_DECOMPTE_FINAL_SOUSTRAITANT" + CodeFacA12 CadreFac = "A12_FACTURE_COTRAITANT" + CodeFacA13 CadreFac = "A13_PROJET_DECOMPTE_MENSUEL_COTRAITANT" + CodeFacA14 CadreFac = "A14_PROJET_DECOMPTE_FINAL_COTRAITANT" + CodeFacA15 CadreFac = "A15_ETAT_ACOMPTE_MOE" + CodeFacA16 CadreFac = "A16_ETAT_ACOMPTE_VALIDE_MOE" + CodeFacA17 CadreFac = "A17_PROJET_DECOMPTE_GENERAL_MOE" + CodeFacA18 CadreFac = "A18_DECOMPTE_GENERAL_MOE" + CodeFacA19 CadreFac = "A19_ETAT_ACOMPTE_VALIDE_MOA" + CodeFacA20 CadreFac = "A20_DECOMPTE_GENERAL_MOA" + CodeFacA21 CadreFac = "A21_DEMANDE_REMBOURSEMENT_TIC" + CodeFacA22 CadreFac = "A22_PROJET_DECOMPTE_GENERAL_FOURNISSEUR_PROCEDURE_TACITE" + CodeFacA23 CadreFac = "A23_DECOMPTE_GENERAL_DEFINITIF_TACITE_FOURNISSEUR" + CodeFacA24 CadreFac = "A24_DECOMPTE_GENERAL_DEFINITIF_TACITE_MOE" + CodeFacA25 CadreFac = "A25_DECOMPTE_GENERAL_DEFINITIF_MOE_PROCEDURE_TACITE" +) + +type RoleUtilisateur string + +const ( + RoleFournisseur RoleUtilisateur = "FOURNISSEUR" + RoleMoe RoleUtilisateur = "MOE" + RoleMoa RoleUtilisateur = "MOA" + RoleValidateur RoleUtilisateur = "VALIDATEUR" + RoleDestinataire RoleUtilisateur = "DESTINATAIRE" +) + +type TypeFacture string + +const ( + TypeFactureFacture TypeFacture = "FACTURE" + TypeFactureAvoir TypeFacture = "AVOIR" + TypeFactureAcompte TypeFacture = "ACOMPTE" +) diff --git a/factures_consultations.go b/factures_consultations.go new file mode 100644 index 0000000..54c0276 --- /dev/null +++ b/factures_consultations.go @@ -0,0 +1,262 @@ +package choruspro + +import ( + "context" + "net/http" +) + +type ConsulterFactureRecipiendaireOptions struct { + CodeLangue CodeLangue `json:"codeLangue,omitempty"` + IdUtilisateurCourant int `json:"idUtilisateurCourant,omitempty"` + IdentifiantFactureCPP int `json:"identifiantFactureCPP,omitempty"` + PaginationLignesPoste *PaginationLignesPosteOptions `json:"rechercheLignePoste,omitempty"` + PaginationPiecesJointes *PaginationPiecesJointesOptions `json:"recherchePj,omitempty"` + PaginationLignesTVA *PaginationLignesRecapTVAOptions `json:"rechercheligneTvaRecap,omitempty"` +} + +type CadreDeFacturation struct { + Code CadreFac `json:"codeCadreFacturation,omitempty"` + CodeServiceMoa string `json:"codeServiceMoa,omitempty"` + CodeServiceMoe string `json:"codeServiceMoe,omitempty"` + CodeValideur1 string `json:"codeValideur1,omitempty"` + CodeValideur2 string `json:"codeValideur2,omitempty"` + DateValidation1 *Date `json:"dateValidation1,omitempty"` + DateValidation2 *Date `json:"dateValidation2,omitempty"` + DesignationMoa string `json:"designationMoa,omitempty"` + DesignationMoe string `json:"designationMoe,omitempty"` + DesignationValideur2 string `json:"designationValideur2,omitempty"` + IdMoa int64 `json:"idMoa,omitempty"` + IdMoe int64 `json:"idMoe,omitempty"` + IdServiceMoa int64 `json:"idServiceMoa,omitempty"` + IdServiceMoe int64 `json:"idServiceMoe,omitempty"` + IdValideur1 int64 `json:"idValideur1,omitempty"` + IdValideur2 int64 `json:"idValideur2,omitempty"` + IdentifiantMoa string `json:"identifiantMoa,omitempty"` + IdentifiantMoe string `json:"identifiantMoe,omitempty"` + NomMoe string `json:"nomMoe,omitempty"` + NomServiceMoa string `json:"nomServiceMoa,omitempty"` + NomServiceMoe string `json:"nomServiceMoe,omitempty"` + NomValideur1 string `json:"nomValideur1,omitempty"` + NomValideur2 string `json:"nomValideur2,omitempty"` + PrenomMoe string `json:"prenomMoe,omitempty"` + PrenomValideur1 string `json:"prenomValideur1,omitempty"` + PrenomValideur2 string `json:"prenomValideur2,omitempty"` + RaisonSocialeMoa string `json:"raisonSocialeMoa,omitempty"` + RaisonSocialeMoe string `json:"raisonSocialeMoe,omitempty"` + RaisonSocialeValideur1 string `json:"raisonSocialeValideur1,omitempty"` + RaisonSocialeValideur2 string `json:"raisonSocialeValideur2,omitempty"` + TypeIdentifiantMoa string `json:"typeIdentifiantMoa,omitempty"` + TypeIdentifiantMoe string `json:"typeIdentifiantMoe,omitempty"` + TypeIdentifiantValideur1 string `json:"typeIdentifiantValideur1,omitempty"` + TypeIdentifiantValideur2 string `json:"typeIdentifiantValideur2,omitempty"` +} + +type Affactureur struct { + Code string `json:"affactureurCode,omitempty"` + CodePays string `json:"affactureurCodePays,omitempty"` + Id int64 `json:"affactureurId,omitempty"` + RaisonSociale string `json:"affactureurRaisonSociale,omitempty"` + TypeIdentifiant string `json:"affactureurTypeIdentifiant,omitempty"` +} + +type PieceJointeFacture struct { + Designation string `json:"pieceJointeDesignation,omitempty"` + Extension string `json:"pieceJointeExtension,omitempty"` + Id int `json:"pieceJointeId,omitempty"` + IdLiaison int `json:"pieceJointeIdLiaison,omitempty"` + NumeroLigneFacture int `json:"pieceJointeNumeroLigneFacture,omitempty"` + TypeCode string `json:"pieceJointeTypeCode,omitempty"` + TypeLibelle string `json:"pieceJointeTypeLibelle,omitempty"` +} + +type LignePoste struct { + Denomination string `json:"lignePosteDenomination,omitempty"` + MontantHtApresRemise float32 `json:"lignePosteMontantHtApresRemise,omitempty"` + MontantRemiseHT float32 `json:"lignePosteMontantRemiseHT,omitempty"` + MontantTtcApresRemise float32 `json:"lignePosteMontantTtcApresRemise,omitempty"` + MontantTva float32 `json:"lignePosteMontantTva,omitempty"` + MontantUnitaireHT float32 `json:"lignePosteMontantUnitaireHT,omitempty"` + Numero int `json:"lignePosteNumero,omitempty"` + Quantite float32 `json:"lignePosteQuantite,omitempty"` + Reference string `json:"lignePosteReference,omitempty"` + TauxTva string `json:"lignePosteTauxTva,omitempty"` + TauxTvaManuel float32 `json:"lignePosteTauxTvaManuel,omitempty"` + UniteCode int `json:"lignePosteUniteCode,omitempty"` + UniteLibelle string `json:"lignePosteUniteLibelle,omitempty"` +} + +type LigneTva struct { + MontantBaseHtParTaux float32 `json:"ligneTvaMontantBaseHtParTaux,omitempty"` + MontantTvaParTaux float32 `json:"ligneTvaMontantTvaParTaux,omitempty"` + TauxManuel float32 `json:"ligneTvaTauxManuel,omitempty"` + TauxRefCode string `json:"ligneTvaTauxRefCode,omitempty"` + TauxRefId int `json:"ligneTvaTauxRefId,omitempty"` + TauxRefLibelle string `json:"ligneTvaTauxRefLibelle,omitempty"` + TauxRefValeur float32 `json:"ligneTvaTauxRefValeur,omitempty"` +} + +type MontantTotal struct { + MontantAPayer float32 `json:"montantAPayer,omitempty"` + MontantHtTotal float32 `json:"montantHtTotal,omitempty"` + MontantRemiseGlobaleTTC float32 `json:"montantRemiseGlobaleTTC,omitempty"` + MontantTVA float32 `json:"montantTVA,omitempty"` + MontantTtcAvantRemiseGlobalTTC float32 `json:"montantTtcAvantRemiseGlobalTTC,omitempty"` + MontantTtcTotal float32 `json:"montantTtcTotal,omitempty"` + MotifRemiseGlobaleTTC string `json:"motifRemiseGlobaleTTC,omitempty"` +} + +type PieceJointePrincipale struct { + IdLiaison int `json:"idLiaisonPieceJointePrincipale,omitempty"` + Id int `json:"idPieceJointePrincipale,omitempty"` +} + +type PiecePrecedente struct { + CadreFacturation string `json:"cadreFacturationPiecePrecedente,omitempty"` + CodeServiceExecutant string `json:"codeServiceExecutantPiecePrecedente,omitempty"` + IdDestinataire int `json:"idDestinatairePiecePrecedente,omitempty"` + Id int `json:"idPiecePrecedente,omitempty"` + IdServiceExecutant int `json:"idServiceExecutantPiecePrecedente,omitempty"` + IdentifiantDestinataire string `json:"identifiantDestinatairePiecePrecedente,omitempty"` + NomServiceExecutant string `json:"nomServiceExecutantPiecePrecedente,omitempty"` + Numero string `json:"numeroPiecePrecedente,omitempty"` + RaisonSocialeDestinataire string `json:"raisonSocialeDestinatairePiecePrecedente,omitempty"` +} + +type PieceSuivante struct { + CadreFacturation string `json:"cadreFacturationPieceSuivante,omitempty"` + Id int `json:"idPieceSuivante,omitempty"` + Numero string `json:"numeroPieceSuivante,omitempty"` +} + +type References struct { + CodeDevise string `json:"codeDeviseFacture,omitempty"` + DateCreationFacture *Date `json:"dateCreationFacture,omitempty"` + DateDepot *Date `json:"dateDepot,omitempty"` + DateEcheancePaiement *Date `json:"dateEcheancePaiement,omitempty"` + DateFacture *Date `json:"dateFacture,omitempty"` + LibelleDevise string `json:"libelleDeviseFacture,omitempty"` + LibelleMotifExonerationTva string `json:"libelleMotifExonerationTva,omitempty"` + ModePaiement string `json:"modePaiement,omitempty"` + MotifExonerationTva string `json:"motifExonerationTva,omitempty"` + NumeroBonCommande string `json:"numeroBonCommande,omitempty"` + NumeroDpMandat string `json:"numeroDpMandat,omitempty"` + NumeroFactureOrigine string `json:"numeroFactureOrigine,omitempty"` + NumeroMarche string `json:"numeroMarche,omitempty"` + TailleTotalePiecesJointes float32 `json:"tailleTotalePiecesJointes,omitempty"` + TypeFacture TypeFacture `json:"typeFacture,omitempty"` + TypeFactureTravaux string `json:"typeFactureTravaux,omitempty"` + TypeTva string `json:"typeTva,omitempty"` +} + +type Destinataire struct { + AdresseCodePays string `json:"adresseDestinataireCodePays,omitempty"` + AdresseCodePostal string `json:"adresseDestinataireCodePostal,omitempty"` + AdresseComplement1 string `json:"adresseDestinataireComplement1,omitempty"` + AdresseComplement2 string `json:"adresseDestinataireComplement2,omitempty"` + AdresseDetail string `json:"adresseDestinataireDetail,omitempty"` + AdresseId int `json:"adresseDestinataireId,omitempty"` + AdresseLibellePays string `json:"adresseDestinataireLibellePays,omitempty"` + AdresseVille string `json:"adresseDestinataireVille,omitempty"` + Code string `json:"codeDestinataire,omitempty"` + CodeServiceExecutant string `json:"codeServiceExecutant,omitempty"` + Etat string `json:"destinataireEtat,omitempty"` + Id int `json:"idDestinataire,omitempty"` + IdServiceExecutant int `json:"idServiceExecutant,omitempty"` + Libelle string `json:"libelleDestinataire,omitempty"` + LibelleServiceExecutant string `json:"libelleServiceExecutant,omitempty"` +} + +type Fournisseur struct { + AdresseCodePays string `json:"adresseFournisseurCodePays,omitempty"` + AdresseCodePostal string `json:"adresseFournisseurCodePostal,omitempty"` + AdresseComplement1 string `json:"adresseFournisseurComplement1,omitempty"` + AdresseComplement2 string `json:"adresseFournisseurComplement2,omitempty"` + AdresseDetail string `json:"adresseFournisseurDetail,omitempty"` + AdresseId int64 `json:"adresseFournisseurId,omitempty"` + AdresseLibellePays string `json:"adresseFournisseurLibellePays,omitempty"` + AdresseVille string `json:"adresseFournisseurVille,omitempty"` + Affactureur Affactureur `json:"affactureur,omitempty"` + Code string `json:"codeFournisseur,omitempty"` + CodeService string `json:"codeServiceFournisseur,omitempty"` + CoordBancairesBicSwift string `json:"coordBancairesBicSwift,omitempty"` + CoordBancairesCodeGuichet string `json:"coordBancairesCodeGuichet,omitempty"` + CoordBancairesCleIban string `json:"coordBancairesFournisseurCleIban,omitempty"` + CoordBancairesCleRib string `json:"coordBancairesFournisseurCleRib,omitempty"` + CoordBancairesCodeBanque string `json:"coordBancairesFournisseurCodeBanque,omitempty"` + CoordBancairesCodePays string `json:"coordBancairesFournisseurCodePays,omitempty"` + CoordBancairesCompteBancaire string `json:"coordBancairesFournisseurCompteBancaire,omitempty"` + CoordBancairesId int64 `json:"coordBancairesFournisseurId,omitempty"` + CoordBancairesLibelle string `json:"coordBancairesFournisseurLibelle,omitempty"` + CoordBancairesType string `json:"coordBancairesFournisseurType,omitempty"` + Designation string `json:"designationFournisseur,omitempty"` + Id int64 `json:"idFournisseur,omitempty"` + IdService int64 `json:"idServiceFournisseur,omitempty"` + LibelleService string `json:"libelleServiceFournisseur,omitempty"` + NumeroRcs string `json:"numeroRcsFournisseur,omitempty"` + TypeIdentifiant string `json:"typeIdentifiantFournisseur,omitempty"` +} + +type ListeLignesDePoste struct { + Lignes []LignePoste `json:"lignePoste,omitempty"` + NbResultatsParPage int64 `json:"nbResultatsParPageLignesPoste,omitempty"` + PageCourante int64 `json:"pageCouranteLignesPoste,omitempty"` + Pages int64 `json:"pagesLignesPoste,omitempty"` + Total int64 `json:"totalLignesPoste,omitempty"` +} + +type ListePiecesJointesFacture struct { + PiecesJointes []PieceJointeFacture `json:"pieceJointe,omitempty"` + NbResultatsParPage int64 `json:"nbResultatsParPageListePiecesJointe,omitempty"` + PageCourante int64 `json:"pageCouranteListePiecesJointe,omitempty"` + Pages int64 `json:"pagesListePiecesJointe,omitempty"` + Total int64 `json:"totalListePiecesJointe,omitempty"` +} + +type ListeLignesRecapTVA struct { + Lignes []LigneTva `json:"ligneTva,omitempty"` + NbResultatsParPage int64 `json:"nbResultatsParPageLignesRecapitulativesTVA,omitempty"` + PageCourante int64 `json:"pageCouranteLignesRecapitulativesTVA,omitempty"` + Pages int64 `json:"pagesLignesRecapitulativesTVA,omitempty"` + Total int64 `json:"totalLignesRecapitulativesTVA,omitempty"` +} + +type Facture struct { + CadreDeFacturation CadreDeFacturation `json:"cadreDeFacturation,omitempty"` + Commentaire string `json:"commentaire,omitempty"` + Destinataire Destinataire `json:"destinataire,omitempty"` + Fournisseur Fournisseur `json:"fournisseur,omitempty"` + IdentifiantFactureCPP int `json:"identifiantFactureCPP,omitempty"` + LignesDePoste *ListeLignesDePoste `json:"lignesDePoste,omitempty"` + ListeDesPiecesJointes *ListePiecesJointesFacture `json:"listeDesPiecesJointes,omitempty"` + ModeDepot string `json:"modeDepot,omitempty"` + MontantTotal MontantTotal `json:"montantTotal,omitempty"` + NumeroFacture string `json:"numeroFacture,omitempty"` + PieceJointePrincipale *PieceJointePrincipale `json:"pieceJointePrincipale,omitempty"` + PiecePrecedente *PiecePrecedente `json:"piecePrecedente,omitempty"` + PieceSuivante *PieceSuivante `json:"pieceSuivante,omitempty"` + RecapitulatifDeTva *ListeLignesRecapTVA `json:"recapitulatifDeTva,omitempty"` + References References `json:"references,omitempty"` + StatutFacture string `json:"statutFacture,omitempty"` +} + +type ConsulterFactureResponse struct { + CodeRetour int `json:"codeRetour,omitempty"` + Facture Facture `json:"facture,omitempty"` + Libelle string `json:"libelle,omitempty"` +} + +func (s *FacturesService) ConsulterFactureParRecipiendaire(ctx context.Context, opts ConsulterFactureRecipiendaireOptions) (*ConsulterFactureResponse, error) { + req, err := s.client.newRequest(ctx, http.MethodPost, "cpro/factures/v1/consulter/recipiendaire", opts) + if err != nil { + return nil, err + } + + res := new(ConsulterFactureResponse) + + err = s.client.doRequest(ctx, req, res) + if err != nil { + return nil, err + } + + return res, nil +} diff --git a/factures_consultations_test.go b/factures_consultations_test.go new file mode 100644 index 0000000..cfe7371 --- /dev/null +++ b/factures_consultations_test.go @@ -0,0 +1,446 @@ +package choruspro + +import ( + "context" + "encoding/json" + "net/http" + "reflect" + "testing" +) + +func TestFacturesService_ConsulterFactureParRecipiendaire(t *testing.T) { + client, mux, teardown := setup() + defer teardown() + + mux.HandleFunc("/cpro/factures/v1/consulter/recipiendaire", func(w http.ResponseWriter, r *http.Request) { + v := new(ListeTypesPieceJointeOptions) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) + testMethod(t, r, http.MethodPost) + w.Write([]byte(`{ + "codeRetour": 1, + "facture": { + "cadreDeFacturation": { + "codeCadreFacturation": "c", + "codeServiceMoa": "c", + "codeServiceMoe": "c", + "codeValideur1": "c", + "codeValideur2": "c", + "dateValidation1": ` + defaultDateStr + `, + "dateValidation2": ` + defaultDateStr + `, + "designationMoa": "d", + "designationMoe": "d", + "designationValideur2": "d", + "idMoa": 1, + "idMoe": 1, + "idServiceMoa": 1, + "idServiceMoe": 1, + "idValideur1": 1, + "idValideur2": 1, + "identifiantMoa": "i", + "identifiantMoe": "i", + "nomMoe": "n", + "nomServiceMoa": "n", + "nomServiceMoe": "n", + "nomValideur1": "n", + "nomValideur2": "n", + "prenomMoe": "p", + "prenomValideur1": "p", + "prenomValideur2": "p", + "raisonSocialeMoa": "r", + "raisonSocialeMoe": "r", + "raisonSocialeValideur1": "r", + "raisonSocialeValideur2": "r", + "typeIdentifiantMoa": "t", + "typeIdentifiantMoe": "t", + "typeIdentifiantValideur1": "t", + "typeIdentifiantValideur2": "t" + }, + "commentaire": "c", + "destinataire": { + "adresseDestinataireCodePays": "a", + "adresseDestinataireCodePostal": "a", + "adresseDestinataireComplement1": "a", + "adresseDestinataireComplement2": "a", + "adresseDestinataireDetail": "a", + "adresseDestinataireId": 1, + "adresseDestinataireLibellePays": "a", + "adresseDestinataireVille": "a", + "codeDestinataire": "c", + "codeServiceExecutant": "c", + "destinataireEtat": "d", + "idDestinataire": 1, + "idServiceExecutant": 1, + "libelleDestinataire": "l", + "libelleServiceExecutant": "l" + }, + "fournisseur": { + "adresseFournisseurCodePays": "a", + "adresseFournisseurCodePostal": "a", + "adresseFournisseurComplement1": "a", + "adresseFournisseurComplement2": "a", + "adresseFournisseurDetail": "a", + "adresseFournisseurId": 1, + "adresseFournisseurLibellePays": "a", + "adresseFournisseurVille": "a", + "affactureur": { + "affactureurCode": "a", + "affactureurCodePays": "a", + "affactureurId": 1, + "affactureurRaisonSociale": "a", + "affactureurTypeIdentifiant": "a" + }, + "codeFournisseur": "c", + "codeServiceFournisseur": "c", + "coordBancairesBicSwift": "c", + "coordBancairesCodeGuichet": "c", + "coordBancairesFournisseurCleIban": "c", + "coordBancairesFournisseurCleRib": "c", + "coordBancairesFournisseurCodeBanque": "c", + "coordBancairesFournisseurCodePays": "c", + "coordBancairesFournisseurCompteBancaire": "c", + "coordBancairesFournisseurId": 1, + "coordBancairesFournisseurLibelle": "c", + "coordBancairesFournisseurType": "c", + "designationFournisseur": "d", + "idFournisseur": 1, + "idServiceFournisseur": 1, + "libelleServiceFournisseur": "l", + "numeroRcsFournisseur": "n", + "typeIdentifiantFournisseur": "t" + }, + "identifiantFactureCPP": 1, + "lignesDePoste": { + "lignePoste": [ + { + "lignePosteDenomination": "l", + "lignePosteMontantHtApresRemise": 1, + "lignePosteMontantRemiseHT": 1, + "lignePosteMontantTtcApresRemise": 1, + "lignePosteMontantTva": 1, + "lignePosteMontantUnitaireHT": 1, + "lignePosteNumero": 1, + "lignePosteQuantite": 1, + "lignePosteReference": "r", + "lignePosteTauxTva": "t", + "lignePosteTauxTvaManuel": 1, + "lignePosteUniteCode": 1, + "lignePosteUniteLibelle": "u" + } + ], + "nbResultatsParPageLignesPoste": 1, + "pageCouranteLignesPoste": 1, + "pagesLignesPoste": 1, + "totalLignesPoste": 1 + }, + "listeDesPiecesJointes": { + "pieceJointe": [ + { + "pieceJointeDesignation": "p", + "pieceJointeExtension": "e", + "pieceJointeId": 1, + "pieceJointeIdLiaison": 1, + "pieceJointeNumeroLigneFacture": 1, + "pieceJointeTypeCode": "t", + "pieceJointeTypeLibelle": "t" + } + ], + "nbResultatsParPageListePiecesJointe": 1, + "pageCouranteListePiecesJointe": 1, + "pagesListePiecesJointe": 1, + "totalListePiecesJointe": 1 + }, + "modeDepot": "m", + "montantTotal": { + "montantAPayer": 1, + "montantHtTotal": 1, + "montantRemiseGlobaleTTC": 1, + "montantTVA": 1, + "montantTtcAvantRemiseGlobalTTC": 1, + "montantTtcTotal": 1, + "motifRemiseGlobaleTTC": "m" + }, + "numeroFacture": "n", + "pieceJointePrincipale": { + "idLiaisonPieceJointePrincipale": 1, + "idPieceJointePrincipale": 1 + }, + "piecePrecedente": { + "cadreFacturationPiecePrecedente": "c", + "codeServiceExecutantPiecePrecedente": "c", + "idDestinatairePiecePrecedente": 1, + "idPiecePrecedente": 1, + "idServiceExecutantPiecePrecedente": 1, + "identifiantDestinatairePiecePrecedente": "i", + "nomServiceExecutantPiecePrecedente": "n", + "numeroPiecePrecedente": "n", + "raisonSocialeDestinatairePiecePrecedente": "r" + }, + "pieceSuivante": { + "cadreFacturationPieceSuivante": "c", + "idPieceSuivante": 1, + "numeroPieceSuivante": "n" + }, + "recapitulatifDeTva": { + "ligneTva": [ + { + "ligneTvaMontantBaseHtParTaux": 1, + "ligneTvaMontantTvaParTaux": 1, + "ligneTvaTauxManuel": 1, + "ligneTvaTauxRefCode": "t", + "ligneTvaTauxRefId": 1, + "ligneTvaTauxRefLibelle": "t", + "ligneTvaTauxRefValeur": 1 + } + ], + "nbResultatsParPageLignesRecapitulativesTVA": 1, + "pageCouranteLignesRecapitulativesTVA": 1, + "pagesLignesRecapitulativesTVA": 1, + "totalLignesRecapitulativesTVA": 1 + }, + "references": { + "codeDeviseFacture": "c", + "dateCreationFacture": ` + defaultDateStr + `, + "dateDepot": ` + defaultDateStr + `, + "dateEcheancePaiement": ` + defaultDateStr + `, + "dateFacture": ` + defaultDateStr + `, + "libelleDeviseFacture": "l", + "libelleMotifExonerationTva": "l", + "modePaiement": "m", + "motifExonerationTva": "m", + "numeroBonCommande": "n", + "numeroDpMandat": "n", + "numeroFactureOrigine": "n", + "numeroMarche": "n", + "tailleTotalePiecesJointes": 1, + "typeFacture": "t", + "typeFactureTravaux": "t", + "typeTva": "t" + }, + "statutFacture": "s" + }, + "libelle": "l" + } + `)) + }) + + ctx := context.Background() + opt := ConsulterFactureRecipiendaireOptions{} + got, err := client.Factures.ConsulterFactureParRecipiendaire(ctx, opt) + + if err != nil { + t.Errorf("Factures.ConsulterFactureParRecipiendaire returned error : %v", err) + } + + want := &ConsulterFactureResponse{ + CodeRetour: 1, + Facture: Facture{ + CadreDeFacturation: CadreDeFacturation{ + Code: "c", + CodeServiceMoa: "c", + CodeServiceMoe: "c", + CodeValideur1: "c", + CodeValideur2: "c", + DateValidation1: &Date{defaultDate}, + DateValidation2: &Date{defaultDate}, + DesignationMoa: "d", + DesignationMoe: "d", + DesignationValideur2: "d", + IdMoa: 1, + IdMoe: 1, + IdServiceMoa: 1, + IdServiceMoe: 1, + IdValideur1: 1, + IdValideur2: 1, + IdentifiantMoa: "i", + IdentifiantMoe: "i", + NomMoe: "n", + NomServiceMoa: "n", + NomServiceMoe: "n", + NomValideur1: "n", + NomValideur2: "n", + PrenomMoe: "p", + PrenomValideur1: "p", + PrenomValideur2: "p", + RaisonSocialeMoa: "r", + RaisonSocialeMoe: "r", + RaisonSocialeValideur1: "r", + RaisonSocialeValideur2: "r", + TypeIdentifiantMoa: "t", + TypeIdentifiantMoe: "t", + TypeIdentifiantValideur1: "t", + TypeIdentifiantValideur2: "t", + }, + Commentaire: "c", + Destinataire: Destinataire{ + AdresseCodePays: "a", + AdresseCodePostal: "a", + AdresseComplement1: "a", + AdresseComplement2: "a", + AdresseDetail: "a", + AdresseId: 1, + AdresseLibellePays: "a", + AdresseVille: "a", + Code: "c", + CodeServiceExecutant: "c", + Etat: "d", + Id: 1, + IdServiceExecutant: 1, + Libelle: "l", + LibelleServiceExecutant: "l", + }, + Fournisseur: Fournisseur{ + AdresseCodePays: "a", + AdresseCodePostal: "a", + AdresseComplement1: "a", + AdresseComplement2: "a", + AdresseDetail: "a", + AdresseId: 1, + AdresseLibellePays: "a", + AdresseVille: "a", + Affactureur: Affactureur{ + Code: "a", + CodePays: "a", + Id: 1, + RaisonSociale: "a", + TypeIdentifiant: "a", + }, + Code: "c", + CodeService: "c", + CoordBancairesBicSwift: "c", + CoordBancairesCodeGuichet: "c", + CoordBancairesCleIban: "c", + CoordBancairesCleRib: "c", + CoordBancairesCodeBanque: "c", + CoordBancairesCodePays: "c", + CoordBancairesCompteBancaire: "c", + CoordBancairesId: 1, + CoordBancairesLibelle: "c", + CoordBancairesType: "c", + Designation: "d", + Id: 1, + IdService: 1, + LibelleService: "l", + NumeroRcs: "n", + TypeIdentifiant: "t", + }, + IdentifiantFactureCPP: 1, + LignesDePoste: &ListeLignesDePoste{ + Lignes: []LignePoste{ + { + Denomination: "l", + MontantHtApresRemise: 1, + MontantRemiseHT: 1, + MontantTtcApresRemise: 1, + MontantTva: 1, + MontantUnitaireHT: 1, + Numero: 1, + Quantite: 1, + Reference: "r", + TauxTva: "t", + TauxTvaManuel: 1, + UniteCode: 1, + UniteLibelle: "u", + }, + }, + NbResultatsParPage: 1, + PageCourante: 1, + Pages: 1, + Total: 1, + }, + ListeDesPiecesJointes: &ListePiecesJointesFacture{ + PiecesJointes: []PieceJointeFacture{ + { + Designation: "p", + Extension: "e", + Id: 1, + IdLiaison: 1, + NumeroLigneFacture: 1, + TypeCode: "t", + TypeLibelle: "t", + }, + }, + NbResultatsParPage: 1, + PageCourante: 1, + Pages: 1, + Total: 1, + }, + ModeDepot: "m", + MontantTotal: MontantTotal{ + MontantAPayer: 1, + MontantHtTotal: 1, + MontantRemiseGlobaleTTC: 1, + MontantTVA: 1, + MontantTtcAvantRemiseGlobalTTC: 1, + MontantTtcTotal: 1, + MotifRemiseGlobaleTTC: "m", + }, + NumeroFacture: "n", + PieceJointePrincipale: &PieceJointePrincipale{ + IdLiaison: 1, + Id: 1, + }, + PiecePrecedente: &PiecePrecedente{ + CadreFacturation: "c", + CodeServiceExecutant: "c", + IdDestinataire: 1, + Id: 1, + IdServiceExecutant: 1, + IdentifiantDestinataire: "i", + NomServiceExecutant: "n", + Numero: "n", + RaisonSocialeDestinataire: "r", + }, + PieceSuivante: &PieceSuivante{ + CadreFacturation: "c", + Id: 1, + Numero: "n", + }, + RecapitulatifDeTva: &ListeLignesRecapTVA{ + Lignes: []LigneTva{ + { + MontantBaseHtParTaux: 1, + MontantTvaParTaux: 1, + TauxManuel: 1, + TauxRefCode: "t", + TauxRefId: 1, + TauxRefLibelle: "t", + TauxRefValeur: 1, + }, + }, + NbResultatsParPage: 1, + PageCourante: 1, + Pages: 1, + Total: 1, + }, + References: References{ + CodeDevise: "c", + DateCreationFacture: &Date{defaultDate}, + DateDepot: &Date{defaultDate}, + DateEcheancePaiement: &Date{defaultDate}, + DateFacture: &Date{defaultDate}, + LibelleDevise: "l", + LibelleMotifExonerationTva: "l", + ModePaiement: "m", + MotifExonerationTva: "m", + NumeroBonCommande: "n", + NumeroDpMandat: "n", + NumeroFactureOrigine: "n", + NumeroMarche: "n", + TailleTotalePiecesJointes: 1, + TypeFacture: "t", + TypeFactureTravaux: "t", + TypeTva: "t", + }, + StatutFacture: "s", + }, + Libelle: "l", + } + if !reflect.DeepEqual(got, want) { + t.Errorf("Factures.ConsulterFactureParRecipiendaire returned %+v, want %+v", got, want) + } + + testNewRequestAndDoRequestFailure(t, "ConsulterFactureParRecipiendaire", client, func() error { + _, err := client.Factures.ConsulterFactureParRecipiendaire(ctx, opt) + return err + }) +} diff --git a/factures_depots.go b/factures_depots.go new file mode 100644 index 0000000..deb3f86 --- /dev/null +++ b/factures_depots.go @@ -0,0 +1,182 @@ +package choruspro + +import ( + "context" + "net/http" +) + +type SoumettreFactureOptions struct { + CadreDeFacturation SoumettreFactureCadreDeFacturation `json:"cadreDeFacturation,omitempty"` + Commentaire string `json:"commentaire,omitempty"` + DateFacture *Date `json:"dateFacture,omitempty"` + Destinataire SoumettreFactureDestinataire `json:"destinataire,omitempty"` + Fournisseur SoumettreFactureFournisseur `json:"fournisseur,omitempty"` + IdUtilisateurCourant int64 `json:"idUtilisateurCourant,omitempty"` + LignesPoste *[]SoumettreFactureLignePoste `json:"lignePoste,omitempty"` + LignesTva *[]SoumettreFactureLigneTva `json:"ligneTva,omitempty"` + ModeDepot string `json:"modeDepot,omitempty"` + MontantTotal SoumettreFactureMontantTotal `json:"montantTotal,omitempty"` + NumeroFactureSaisi string `json:"numeroFactureSaisi,omitempty"` + PiecesJointesComplementaires *[]PieceJointeComplementaire `json:"pieceJointeComplementaire,omitempty"` + PiecesJointesPrincipales SoumettreFacturePJPrincipale `json:"pieceJointePrincipale,omitempty"` + References SoumettreFactureReferences `json:"references,omitempty"` +} + +type SoumettreFactureCadreDeFacturation struct { + Code CadreFac `json:"codeCadreFacturation,omitempty"` + CodeServiceValideur string `json:"codeServiceValideur,omitempty"` + CodeStructureValideur string `json:"codeStructureValideur,omitempty"` +} + +type SoumettreFactureDestinataire struct { + Code string `json:"codeDestinataire,omitempty"` + CodeServiceExecutant string `json:"codeServiceExecutant,omitempty"` +} + +type SoumettreFactureFournisseur struct { + CodeCoordonneesBancairesFournisseur int64 `json:"codeCoordonneesBancairesFournisseur,omitempty"` + IdFournisseur int64 `json:"idFournisseur,omitempty"` + IdServiceFournisseur int64 `json:"idServiceFournisseur,omitempty"` +} + +type SoumettreFactureLignePoste struct { + Denomination string `json:"lignePosteDenomination,omitempty"` + MontantRemiseHT float32 `json:"lignePosteMontantRemiseHT,omitempty"` + MontantUnitaireHT float32 `json:"lignePosteMontantUnitaireHT,omitempty"` + Numero int `json:"lignePosteNumero,omitempty"` + Quantite float32 `json:"lignePosteQuantite,omitempty"` + Reference string `json:"lignePosteReference,omitempty"` + TauxTva string `json:"lignePosteTauxTva,omitempty"` + TauxTvaManuel float32 `json:"lignePosteTauxTvaManuel,omitempty"` + Unite string `json:"lignePosteUnite,omitempty"` +} + +type SoumettreFactureLigneTva struct { + MontantBaseHtParTaux float32 `json:"ligneTvaMontantBaseHtParTaux,omitempty"` + MontantTvaParTaux float32 `json:"ligneTvaMontantTvaParTaux,omitempty"` + Taux string `json:"ligneTvaTaux,omitempty"` + TauxManuel float32 `json:"ligneTvaTauxManuel,omitempty"` +} + +type SoumettreFactureMontantTotal struct { + MontantAPayer float32 `json:"montantAPayer,omitempty"` + MontantHtTotal float32 `json:"montantHtTotal,omitempty"` + MontantRemiseGlobaleTTC float32 `json:"montantRemiseGlobaleTTC,omitempty"` + MontantTVA float32 `json:"montantTVA,omitempty"` + MontantTtcTotal float32 `json:"montantTtcTotal,omitempty"` + MotifRemiseGlobaleTTC string `json:"motifRemiseGlobaleTTC,omitempty"` +} + +type PieceJointeComplementaire struct { + Designation string `json:"pieceJointeComplementaireDesignation,omitempty"` + Id int64 `json:"pieceJointeComplementaireId,omitempty"` + IdLiaison int64 `json:"pieceJointeComplementaireIdLiaison,omitempty"` + NumeroLigneFacture int64 `json:"pieceJointeComplementaireNumeroLigneFacture,omitempty"` + Type string `json:"pieceJointeComplementaireType,omitempty"` +} + +type SoumettreFacturePJPrincipale struct { + Designation string `json:"pieceJointePrincipaleDesignation,omitempty"` + Id int64 `json:"pieceJointePrincipaleId,omitempty"` +} + +type SoumettreFactureReferences struct { + DeviseFacture string `json:"deviseFacture,omitempty"` + ModePaiement string `json:"modePaiement,omitempty"` + MotifExonerationTva string `json:"motifExonerationTva,omitempty"` + NumeroBonCommande string `json:"numeroBonCommande,omitempty"` + NumeroFactureOrigine string `json:"numeroFactureOrigine,omitempty"` + NumeroMarche string `json:"numeroMarche,omitempty"` + TypeFacture string `json:"typeFacture,omitempty"` + TypeTva string `json:"typeTva,omitempty"` +} + +type SoumettreFactureResponse struct { + CodeRetour int `json:"codeRetour,omitempty"` + DateDepot *Date `json:"dateDepot,omitempty"` + EmpreinteCertificatDepot string `json:"empreinteCertificatDepot,omitempty"` + IdentifiantFactureCPP int64 `json:"identifiantFactureCPP,omitempty"` + IdentifiantStructure string `json:"identifiantStructure,omitempty"` + Libelle string `json:"libelle,omitempty"` + NumeroFacture string `json:"numeroFacture,omitempty"` + StatutFacture string `json:"statutFacture,omitempty"` +} + +func (s *FacturesService) SoumettreFacture(ctx context.Context, opts SoumettreFactureOptions) (*SoumettreFactureResponse, error) { + req, err := s.client.newRequest(ctx, http.MethodPost, "cpro/factures/v1/soumettre", opts) + if err != nil { + return nil, err + } + + res := new(SoumettreFactureResponse) + + err = s.client.doRequest(ctx, req, res) + if err != nil { + return nil, err + } + + return res, nil +} + +type DeposerFluxFactureOptions struct { + AvecSignature bool `json:"avecSignature,omitempty"` + FichierFlux string `json:"fichierFlux,omitempty"` + IdUtilisateurCourant int64 `json:"idUtilisateurCourant,omitempty"` + NomFichier string `json:"nomFichier,omitempty"` + SyntaxeFlux SyntaxeFlux `json:"syntaxeFlux,omitempty"` +} + +type DeposerFluxFactureResponse struct { + CodeRetour int `json:"codeRetour,omitempty"` + DateDepot *Date `json:"dateDepot,omitempty"` + Libelle string `json:"libelle,omitempty"` + NumeroFluxDepot string `json:"numeroFluxDepot,omitempty"` + SyntaxeFlux SyntaxeFlux `json:"syntaxeFlux,omitempty"` +} + +func (s *FacturesService) DeposerFlux(ctx context.Context, opts DeposerFluxFactureOptions) (*DeposerFluxFactureResponse, error) { + req, err := s.client.newRequest(ctx, http.MethodPost, "cpro/factures/v1/deposer/flux", opts) + if err != nil { + return nil, err + } + + res := new(DeposerFluxFactureResponse) + + err = s.client.doRequest(ctx, req, res) + if err != nil { + return nil, err + } + + return res, nil +} + +type CompleterFactureOptions struct { + Commentaire string `json:"commentaire,omitempty"` + IdUtilisateurCourant int64 `json:"idUtilisateurCourant,omitempty"` + IdentifiantFactureCPP int64 `json:"identifiantFactureCPP,omitempty"` + PiecesJointesComplementaires []*PieceJointeComplementaire `json:"pieceJointeComplementaire,omitempty"` +} + +type CompleterFactureResponse struct { + CodeRetour int `json:"codeRetour,omitempty"` + DateTraitement *Date `json:"dateTraitement,omitempty"` + IdentifiantFactureCPP int64 `json:"identifiantFactureCPP,omitempty"` + Libelle string `json:"libelle,omitempty"` + NumeroFacture string `json:"numeroFacture,omitempty"` +} + +func (s *FacturesService) CompleterFacture(ctx context.Context, opts CompleterFactureOptions) (*CompleterFactureResponse, error) { + req, err := s.client.newRequest(ctx, http.MethodPost, "cpro/factures/v1/completer", opts) + if err != nil { + return nil, err + } + + res := new(CompleterFactureResponse) + + err = s.client.doRequest(ctx, req, res) + if err != nil { + return nil, err + } + + return res, nil +} diff --git a/factures_depots_test.go b/factures_depots_test.go new file mode 100644 index 0000000..bc267f4 --- /dev/null +++ b/factures_depots_test.go @@ -0,0 +1,148 @@ +package choruspro + +import ( + "context" + "encoding/json" + "net/http" + "reflect" + "testing" +) + +func TestFacturesService_SoumettreFacture(t *testing.T) { + client, mux, teardown := setup() + defer teardown() + + mux.HandleFunc("/cpro/factures/v1/soumettre", func(w http.ResponseWriter, r *http.Request) { + v := new(SoumettreFactureOptions) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) + testMethod(t, r, http.MethodPost) + w.Write([]byte(`{ + "codeRetour": 1, + "dateDepot": ` + `"2023-01-01"` + `, + "empreinteCertificatDepot": "e", + "identifiantFactureCPP": 1, + "identifiantStructure": "i", + "libelle": "l", + "numeroFacture": "F001", + "statutFacture": "s" + }`)) + }) + + ctx := context.Background() + opt := SoumettreFactureOptions{ + References: SoumettreFactureReferences{ + NumeroFactureOrigine: "F001", + }, + } + got, err := client.Factures.SoumettreFacture(ctx, opt) + + if err != nil { + t.Errorf("Factures.SoumettreFacture returned error : %v", err) + } + + want := &SoumettreFactureResponse{ + CodeRetour: 1, + DateDepot: &Date{defaultDate}, + EmpreinteCertificatDepot: "e", + IdentifiantFactureCPP: 1, + IdentifiantStructure: "i", + Libelle: "l", + NumeroFacture: "F001", + StatutFacture: "s", + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("Factures.SoumettreFacture returned %+v, want %+v", got, want) + } + + testNewRequestAndDoRequestFailure(t, "SoumettreFacture", client, func() error { + _, err := client.Factures.SoumettreFacture(ctx, opt) + return err + }) +} + +func TestFacturesService_DeposerFlux(t *testing.T) { + client, mux, teardown := setup() + defer teardown() + + mux.HandleFunc("/cpro/factures/v1/deposer/flux", func(w http.ResponseWriter, r *http.Request) { + v := new(DeposerFluxFactureOptions) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) + testMethod(t, r, http.MethodPost) + w.Write([]byte(`{ + "codeRetour": 1, + "dateDepot": ` + defaultDateStr + `, + "libelle": "l", + "numeroFluxDepot": "n", + "syntaxeFlux": "s" + }`)) + }) + + ctx := context.Background() + opt := DeposerFluxFactureOptions{} + got, err := client.Factures.DeposerFlux(ctx, opt) + + if err != nil { + t.Errorf("Factures.DeposerFlux returned error : %v", err) + } + + want := &DeposerFluxFactureResponse{ + CodeRetour: 1, + DateDepot: &Date{defaultDate}, + Libelle: "l", + NumeroFluxDepot: "n", + SyntaxeFlux: "s", + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("Factures.DeposerFlux returned %+v, want %+v", got, want) + } + + testNewRequestAndDoRequestFailure(t, "DeposerFlux", client, func() error { + _, err := client.Factures.DeposerFlux(ctx, opt) + return err + }) +} + +func TestFacturesService_CompleterFacture(t *testing.T) { + client, mux, teardown := setup() + defer teardown() + + mux.HandleFunc("/cpro/factures/v1/completer", func(w http.ResponseWriter, r *http.Request) { + v := new(CompleterFactureOptions) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) + testMethod(t, r, http.MethodPost) + w.Write([]byte(`{ + "codeRetour": 1, + "dateTraitement": ` + defaultDateStr + `, + "identifiantFactureCPP": 1, + "libelle": "l", + "numeroFacture": "n" + }`)) + }) + + ctx := context.Background() + opt := CompleterFactureOptions{} + got, err := client.Factures.CompleterFacture(ctx, opt) + + if err != nil { + t.Errorf("Factures.CompleterFacture returned error : %v", err) + } + + want := &CompleterFactureResponse{ + CodeRetour: 1, + DateTraitement: &Date{defaultDate}, + IdentifiantFactureCPP: 1, + Libelle: "l", + NumeroFacture: "n", + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("Factures.CompleterFacture returned %+v, want %+v", got, want) + } + + testNewRequestAndDoRequestFailure(t, "CompleterFacture", client, func() error { + _, err := client.Factures.CompleterFacture(ctx, opt) + return err + }) +} diff --git a/factures_misc.go b/factures_misc.go new file mode 100644 index 0000000..8108122 --- /dev/null +++ b/factures_misc.go @@ -0,0 +1,37 @@ +package choruspro + +import ( + "context" + "net/http" +) + +type TelechargerGroupeFactureOptions struct { + // 2 values allowed: "OUI" or "NON" + AvecPiecesJointesComplementaires string `json:"avecPiecesJointesComplementaires,omitempty"` + Format FormatFichier `json:"format,omitempty"` + IdEspace int64 `json:"idEspace,omitempty"` + IdUtilisateurCourant int64 `json:"idUtilisateurCourant,omitempty"` + ListeFactures []*IdFacture `json:"listeFacture,omitempty"` +} + +type TelechargerGroupeFactureResponse struct { + CodeRetour int `json:"codeRetour,omitempty"` + FichierResultat string `json:"fichierResultat,omitempty"` // base64 encoded + Libelle string `json:"libelle,omitempty"` +} + +func (s *FacturesService) TelechargerGroupe(ctx context.Context, opts TraiterFactureAValiderOptions) (*TelechargerGroupeFactureResponse, error) { + req, err := s.client.newRequest(ctx, http.MethodPost, "cpro/factures/v1/telecharger/groupe", opts) + if err != nil { + return nil, err + } + + res := new(TelechargerGroupeFactureResponse) + + err = s.client.doRequest(ctx, req, res) + if err != nil { + return nil, err + } + + return res, nil +} diff --git a/factures_misc_test.go b/factures_misc_test.go new file mode 100644 index 0000000..1063802 --- /dev/null +++ b/factures_misc_test.go @@ -0,0 +1,48 @@ +package choruspro + +import ( + "context" + "encoding/json" + "net/http" + "reflect" + "testing" +) + +func TestFacturesService_TelechargerGroupe(t *testing.T) { + client, mux, teardown := setup() + defer teardown() + + mux.HandleFunc("/cpro/factures/v1/telecharger/groupe", func(w http.ResponseWriter, r *http.Request) { + v := new(TraiterFactureAValiderOptions) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) + testMethod(t, r, http.MethodPost) + w.Write([]byte(`{ + "codeRetour": 1, + "fichierResultat": "f", + "libelle": "l" + }`)) + }) + + ctx := context.Background() + opt := TraiterFactureAValiderOptions{} + got, err := client.Factures.TelechargerGroupe(ctx, opt) + + if err != nil { + t.Errorf("Factures.TelechargerGroupe returned error : %v", err) + } + + want := &TelechargerGroupeFactureResponse{ + CodeRetour: 1, + FichierResultat: "f", + Libelle: "l", + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("Factures.TelechargerGroupe returned %+v, want %+v", got, want) + } + + testNewRequestAndDoRequestFailure(t, "TelechargerGroupe", client, func() error { + _, err := client.Factures.TelechargerGroupe(ctx, opt) + return err + }) +} diff --git a/factures_recherches.go b/factures_recherches.go new file mode 100644 index 0000000..a39eb49 --- /dev/null +++ b/factures_recherches.go @@ -0,0 +1,254 @@ +package choruspro + +import ( + "context" + "net/http" + "time" +) + +type RechercherDemandePaiementOptions struct { + CadreFacturation CadreFac `json:"cadreFacturation,omitempty"` + + // 2 value possible : "DEMANDE_PAIEMENT" or "DP_ARCHIVE" + DpOuDpArchive string `json:"dpOuDpArchive,omitempty"` + + IdServiceDestinataire int64 `json:"idServiceDestinataire,omitempty"` + IdServiceFournisseur int64 `json:"idServiceFournisseur,omitempty"` + IdServiceMoa int64 `json:"idServiceMoa,omitempty"` + IdServiceMoe int64 `json:"idServiceMoe,omitempty"` + MontantAPayerMax float32 `json:"montantAPayerMax,omitempty"` + MontantAPayerMin float32 `json:"montantAPayerMin,omitempty"` + MontantHTMax float32 `json:"montantHTMax,omitempty"` + MontantHTMin float32 `json:"montantHTMin,omitempty"` + MontantTTCMax float32 `json:"montantTTCMax,omitempty"` + MontantTTCMin float32 `json:"montantTTCMin,omitempty"` + NumeroBonCommande string `json:"numeroBonCommande,omitempty"` + NumeroDossierFacturation string `json:"numeroDossierFacturation,omitempty"` + NumeroDpMandat string `json:"numeroDpMandat,omitempty"` + NumeroFacture string `json:"numeroFacture,omitempty"` + NumeroFactureMemoire string `json:"numeroFactureMemoire,omitempty"` + NumeroFactureOrigine string `json:"numeroFactureOrigine,omitempty"` + NumeroMarche string `json:"numeroMarche,omitempty"` + PeriodeDateDepotAu *Date `json:"periodeDateDepotAu,omitempty"` + PeriodeDateDepotDu *Date `json:"periodeDateDepotDu,omitempty"` + PeriodeDateFournisseurAu *Date `json:"periodeDateFournisseurAu,omitempty"` + PeriodeDateFournisseurDu *Date `json:"periodeDateFournisseurDu,omitempty"` + PeriodeDateHeureEtatCourantAu *time.Time `json:"periodeDateHeureEtatCourantAu,omitempty"` + PeriodeDateHeureEtatCourantDu *time.Time `json:"periodeDateHeureEtatCourantDu,omitempty"` + RechercheSirenDestinataire bool `json:"rechercheSirenDestinataire,omitempty"` + RechercheSirenFournisseur bool `json:"rechercheSirenFournisseur,omitempty"` + RoleUtilisateur RoleUtilisateur `json:"roleUtilisateur,omitempty"` + StatutCourant string `json:"statutCourant,omitempty"` + TypeDemandePaiement string `json:"typeDemandePaiement,omitempty"` + TypeFacture TypeFacture `json:"typeFacture,omitempty"` + + // Values available using Transverses.RecupererTypesFactureTravaux() + TypeFactureTravaux string `json:"typeFactureTravaux,omitempty"` + + StructureDestinataire *StructureDestinataireParam `json:"structureDestinataire,omitempty"` + StructureFournisseur *StructureFournisseurParam `json:"structureFournisseur,omitempty"` + StructureMoa *StructureMoaParam `json:"structureMoa,omitempty"` + StructureMoe *StructureMoeParam `json:"structureMoe,omitempty"` + StructureValideur *StructureValideurParam `json:"structureValideur,omitempty"` +} + +type StructureDestinataireParam struct { + IdStructure int64 `json:"idStructureDestinataire,omitempty"` + IdentifiantStructure string `json:"identifiantStructureDestinataire,omitempty"` + TypeIdentifiantStructure string `json:"typeIdentifiantStructureDestinataire,omitempty"` +} + +type StructureFournisseurParam struct { + IdStructure int64 `json:"idStructureFournisseur,omitempty"` + IdentifiantStructure string `json:"identifiantStructureFournisseur,omitempty"` + TypeIdentifiantStructure string `json:"typeIdentifiantStructureFournisseur,omitempty"` +} + +type StructureMoaParam struct { + IdStructure int64 `json:"idStructureMoa,omitempty"` + IdentifiantStructure string `json:"identifiantStructureMoa,omitempty"` + TypeIdentifiantStructure string `json:"typeIdentifiantStructureMoa,omitempty"` +} + +type StructureMoeParam struct { + IdStructure int64 `json:"idStructureMoe,omitempty"` + IdentifiantStructure string `json:"identifiantStructureMoe,omitempty"` + TypeIdentifiantStructure string `json:"typeIdentifiantStructureMoe,omitempty"` +} + +type StructureValideurParam struct { + IdStructure int64 `json:"idStructureValideur,omitempty"` + IdentifiantStructure string `json:"identifiantStructureValideur,omitempty"` + TypeIdentifiantStructure string `json:"typeIdentifiantStructureValideur,omitempty"` +} + +type RechercherDemandePaiementResponse struct { + CodeRetour int `json:"codeRetour,omitempty"` + Libelle string `json:"libelle,omitempty"` + DemandesPaiement *[]DemandePaiement `json:"listeDemandePaiement,omitempty"` +} + +type DemandePaiement struct { + CadreFacturation CadreFac `json:"cadreFacturation,omitempty"` + CodeJuridiction string `json:"codeJuridiction,omitempty"` + CodeServiceDestinataire string `json:"codeServiceDestinataire,omitempty"` + CodeServiceSollicitation string `json:"codeServiceSollicitation,omitempty"` + CommentaireEtatCourant string `json:"commentaireEtatCourant,omitempty"` + DateDepot *Date `json:"dateDepot,omitempty"` + DateFournisseur *Date `json:"dateFournisseur,omitempty"` + DateHeureEtatCourant *time.Time `json:"dateHeureEtatCourant,omitempty"` + DpOuDpArchive string `json:"dpOuDpArchive,omitempty"` + EtatCourant string `json:"etatCourant,omitempty"` + IdDemandePaiement int64 `json:"idDemandePaiement,omitempty"` + IdDossierFacturation int64 `json:"idDossierFacturation,omitempty"` + IdServiceDestinataire int64 `json:"idServiceDestinataire,omitempty"` + IdServiceFournisseur int64 `json:"idServiceFournisseur,omitempty"` + IdServiceMoa int64 `json:"idServiceMoa,omitempty"` + IdServiceMoe int64 `json:"idServiceMoe,omitempty"` + IdStructureDestinataire int64 `json:"idStructureDestinataire,omitempty"` + IdStructureFournisseur int64 `json:"idStructureFournisseur,omitempty"` + IdStructureMoa int64 `json:"idStructureMoa,omitempty"` + IdStructureMoe int64 `json:"idStructureMoe,omitempty"` + IdStructureValideur1 int64 `json:"idStructureValideur1,omitempty"` + IdStructureValideur2 int64 `json:"idStructureValideur2,omitempty"` + IdentifiantStructureDestinataire string `json:"identifiantStructureDestinataire,omitempty"` + IdentifiantStructureFournisseur string `json:"identifiantStructureFournisseur,omitempty"` + LibelleCodePostaleDeptDR string `json:"libelleCodePostaleDeptDR,omitempty"` + MontantAPayer float32 `json:"montantAPayer,omitempty"` + MontantHT float32 `json:"montantHT,omitempty"` + MontantTTC float32 `json:"montantTTC,omitempty"` + NomServiceDestinataire string `json:"nomServiceDestinataire,omitempty"` + NomServiceSollicitation string `json:"nomServiceSollicitation,omitempty"` + NombreResultatTotal string `json:"nombreResultatTotal,omitempty"` + NumeroBonCommande string `json:"numeroBonCommande,omitempty"` + NumeroDemandePaiement string `json:"numeroDemandePaiement,omitempty"` + NumeroDossierFacturation string `json:"numeroDossierFacturation,omitempty"` + NumeroDpMandat string `json:"numeroDpMandat,omitempty"` + NumeroFactureOrigine string `json:"numeroFactureOrigine,omitempty"` + NumeroMarche string `json:"numeroMarche,omitempty"` + RaisonSocialeDeptDR string `json:"raisonSocialeDeptDR,omitempty"` + RaisonSocialeJuridiction string `json:"raisonSocialeJuridiction,omitempty"` + RaisonSocialeTGI string `json:"raisonSocialeTGI,omitempty"` + SiretDestinataireQualif string `json:"siretDestinataireQualif,omitempty"` + SiretFournisseurQualif string `json:"siretFournisseurQualif,omitempty"` + TypeDemandePaiement string `json:"typeDemandePaiement,omitempty"` + TypeFacture TypeFacture `json:"typeFacture,omitempty"` + TypeFactureTravaux string `json:"typeFactureTravaux,omitempty"` +} + +func (s *FacturesService) RechercherDemandePaiement(ctx context.Context, opts RechercherDemandePaiementOptions) (*RechercherDemandePaiementResponse, error) { + req, err := s.client.newRequest(ctx, http.MethodPost, "cpro/factures/v1/rechercher/demandePaiement", opts) + if err != nil { + return nil, err + } + + res := new(RechercherDemandePaiementResponse) + + err = s.client.doRequest(ctx, req, res) + if err != nil { + return nil, err + } + + return res, nil +} + +type RechercherFactureRecipiendaireOptions struct { + CadreFacturation CadreFac `json:"cadreFacturation,omitempty"` + FactureTelechargeeParDestinataire bool `json:"factureTelechargeeParDestinataire,omitempty"` + IdDestinataire int64 `json:"idDestinataire,omitempty"` + IdServiceExecutant int64 `json:"idServiceExecutant,omitempty"` + IdStructureValideur int64 `json:"idStructureValideur,omitempty"` + IdUtilisateurCourant int64 `json:"idUtilisateurCourant,omitempty"` + ListeFournisseurs []*FournisseurParam `json:"listeFournisseurs,omitempty"` + ListeTypesFacture []string `json:"listeTypeFacture,omitempty"` + ListeTypesFactureTravaux []string `json:"listeTypeFactureTravaux,omitempty"` + MontantAPayerMax float32 `json:"montantApayerMax,omitempty"` + MontantAPayerMin float32 `json:"montantApayerMin,omitempty"` + MontantHTMax float32 `json:"montantHTMax,omitempty"` + MontantHTMin float32 `json:"montantHTMin,omitempty"` + MontantTTCMax float32 `json:"montantTTCMax,omitempty"` + MontantTTCMin float32 `json:"montantTTCMin,omitempty"` + NumeroBonCommande string `json:"numeroBonCommande,omitempty"` + NumeroFacture string `json:"numeroFacture,omitempty"` + NumeroMarche string `json:"numeroMarche,omitempty"` + Pagination *PaginationOptions `json:"paramRecherche,omitempty"` + PeriodeDateDepotAu *Date `json:"periodeDateDepotAu,omitempty"` + PeriodeDateDepotDu *Date `json:"periodeDateDepotDu,omitempty"` + PeriodeDateFactureAu *Date `json:"periodeDateFactureAu,omitempty"` + PeriodeDateFactureDu *Date `json:"periodeDateFactureDu,omitempty"` + PeriodeDateHeureEtatCourantAu *time.Time `json:"periodeDateHeureEtatCourantAu,omitempty"` + PeriodeDateHeureEtatCourantDu *time.Time `json:"periodeDateHeureEtatCourantDu,omitempty"` + RechercheSirenFournisseur bool `json:"rechercheSirenFournisseur,omitempty"` + RecupererTaille bool `json:"recupererTaille,omitempty"` + StatutCourant []string `json:"statutCourant,omitempty"` + TypeDemandePaiement string `json:"typeDemandePaiement,omitempty"` +} + +type FournisseurParam struct { + IdFournisseur int64 `json:"idFournisseur,omitempty"` + ListeIdService []int64 `json:"listeIdService,omitempty"` +} + +type RechercherFactureRecipiendaireResponse struct { + CodeRetour int `json:"codeRetour,omitempty"` + Libelle string `json:"libelle,omitempty"` + Factures *[]FactureRecherche `json:"listeFactures,omitempty"` + NbResultatsParPage int `json:"nbResultatsParPage,omitempty"` + PageCourante int `json:"pageCourante,omitempty"` + Pages int `json:"pages,omitempty"` + Total int `json:"total,omitempty"` +} + +type FactureRecherche struct { + CodeDestinataire string `json:"codeDestinataire,omitempty"` + CodeFournisseur string `json:"codeFournisseur,omitempty"` + CodeMOA string `json:"codeMOA,omitempty"` + CodeMOE string `json:"codeMOE,omitempty"` + CodeServiceExecutant string `json:"codeServiceExecutant,omitempty"` + CodeServiceFournisseur string `json:"codeServiceFournisseur,omitempty"` + CommentaireEtatCourant string `json:"commentaireEtatCourant,omitempty"` + DateDepot *Date `json:"dateDepot,omitempty"` + DateFacture *Date `json:"dateFacture,omitempty"` + DateHeureEtatCourant *time.Time `json:"dateHeureEtatCourant,omitempty"` + DesignationDestinataire string `json:"designationDestinataire,omitempty"` + DesignationFournisseur string `json:"designationFournisseur,omitempty"` + DesignationMOA string `json:"designationMOA,omitempty"` + DesignationMOE string `json:"designationMOE,omitempty"` + Devise string `json:"devise,omitempty"` + FactureTelechargeeParDestinataire bool `json:"factureTelechargeeParDestinataire,omitempty"` + IdDestinataire int64 `json:"idDestinataire,omitempty"` + IdFacture int64 `json:"idFacture,omitempty"` + IdServiceExecutant int64 `json:"idServiceExecutant,omitempty"` + MontantAPayer float32 `json:"montantAPayer,omitempty"` + MontantHT float32 `json:"montantHT,omitempty"` + MontantTTC float32 `json:"montantTTC,omitempty"` + NomServiceExecutant string `json:"nomServiceExecutant,omitempty"` + NomServiceFournisseur string `json:"nomServiceFournisseur,omitempty"` + NumeroBonCommande string `json:"numeroBonCommande,omitempty"` + NumeroFacture string `json:"numeroFacture,omitempty"` + NumeroMarche string `json:"numeroMarche,omitempty"` + Statut string `json:"statut,omitempty"` + Taille int64 `json:"taille,omitempty"` + TypeDemandePaiement string `json:"typeDemandePaiement,omitempty"` + TypeFacture TypeFacture `json:"typeFacture,omitempty"` + TypeFactureTravaux string `json:"typeFactureTravaux,omitempty"` + TypeIdentifiantFournisseur string `json:"typeIdentifiantFournisseur,omitempty"` + TypeIdentifiantMOA string `json:"typeIdentifiantMOA,omitempty"` + TypeIdentifiantMOE string `json:"typeIdentifiantMOE,omitempty"` +} + +func (s *FacturesService) RechercherFactureParRecipiendaire(ctx context.Context, opts RechercherFactureRecipiendaireOptions) (*RechercherFactureRecipiendaireResponse, error) { + req, err := s.client.newRequest(ctx, http.MethodPost, "cpro/factures/v1/rechercher/recipiendaire", opts) + if err != nil { + return nil, err + } + + res := new(RechercherFactureRecipiendaireResponse) + + err = s.client.doRequest(ctx, req, res) + if err != nil { + return nil, err + } + + return res, nil +} diff --git a/factures_recherches_test.go b/factures_recherches_test.go new file mode 100644 index 0000000..e8bf61a --- /dev/null +++ b/factures_recherches_test.go @@ -0,0 +1,267 @@ +package choruspro + +import ( + "context" + "encoding/json" + "net/http" + "reflect" + "testing" +) + +func TestFacturesService_RechercherDemandePaiement(t *testing.T) { + client, mux, teardown := setup() + defer teardown() + + mux.HandleFunc("/cpro/factures/v1/rechercher/demandePaiement", func(w http.ResponseWriter, r *http.Request) { + v := new(RechercherDemandePaiementOptions) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) + testMethod(t, r, http.MethodPost) + w.Write([]byte(`{ + "codeRetour": 1, + "libelle": "l", + "listeDemandePaiement": [ + { + "cadreFacturation": "c", + "codeJuridiction": "c", + "codeServiceDestinataire": "c", + "codeServiceSollicitation": "c", + "commentaireEtatCourant": "c", + "dateDepot": ` + defaultDateStr + `, + "dateFournisseur": ` + defaultDateStr + `, + "dateHeureEtatCourant": ` + defaultDateTimeStr + `, + "dpOuDpArchive": "d", + "etatCourant": "e", + "idDemandePaiement": 1, + "idDossierFacturation": 1, + "idServiceDestinataire": 1, + "idServiceFournisseur": 1, + "idServiceMoa": 1, + "idServiceMoe": 1, + "idStructureDestinataire": 1, + "idStructureFournisseur": 1, + "idStructureMoa": 1, + "idStructureMoe": 1, + "idStructureValideur1": 1, + "idStructureValideur2": 1, + "identifiantStructureDestinataire": "i", + "identifiantStructureFournisseur": "i", + "libelleCodePostaleDeptDR": "l", + "montantAPayer": 1, + "montantHT": 1, + "montantTTC": 1, + "nomServiceDestinataire": "n", + "nomServiceSollicitation": "n", + "nombreResultatTotal": "n", + "numeroBonCommande": "n", + "numeroDemandePaiement": "n", + "numeroDossierFacturation": "n", + "numeroDpMandat": "n", + "numeroFactureOrigine": "n", + "numeroMarche": "n", + "raisonSocialeDeptDR": "r", + "raisonSocialeJuridiction": "r", + "raisonSocialeTGI": "r", + "siretDestinataireQualif": "s", + "siretFournisseurQualif": "s", + "typeDemandePaiement": "t", + "typeFacture": "t", + "typeFactureTravaux": "t" + } + ] + }`)) + }) + + ctx := context.Background() + opt := RechercherDemandePaiementOptions{} + got, err := client.Factures.RechercherDemandePaiement(ctx, opt) + + if err != nil { + t.Errorf("Factures.RechercherDemandePaiement returned error : %v", err) + } + + want := &RechercherDemandePaiementResponse{ + CodeRetour: 1, + Libelle: "l", + DemandesPaiement: &[]DemandePaiement{ + { + CadreFacturation: "c", + CodeJuridiction: "c", + CodeServiceDestinataire: "c", + CodeServiceSollicitation: "c", + CommentaireEtatCourant: "c", + DateDepot: &Date{defaultDate}, + DateFournisseur: &Date{defaultDate}, + DateHeureEtatCourant: &defaultDate, + DpOuDpArchive: "d", + EtatCourant: "e", + IdDemandePaiement: 1, + IdDossierFacturation: 1, + IdServiceDestinataire: 1, + IdServiceFournisseur: 1, + IdServiceMoa: 1, + IdServiceMoe: 1, + IdStructureDestinataire: 1, + IdStructureFournisseur: 1, + IdStructureMoa: 1, + IdStructureMoe: 1, + IdStructureValideur1: 1, + IdStructureValideur2: 1, + IdentifiantStructureDestinataire: "i", + IdentifiantStructureFournisseur: "i", + LibelleCodePostaleDeptDR: "l", + MontantAPayer: 1, + MontantHT: 1, + MontantTTC: 1, + NomServiceDestinataire: "n", + NomServiceSollicitation: "n", + NombreResultatTotal: "n", + NumeroBonCommande: "n", + NumeroDemandePaiement: "n", + NumeroDossierFacturation: "n", + NumeroDpMandat: "n", + NumeroFactureOrigine: "n", + NumeroMarche: "n", + RaisonSocialeDeptDR: "r", + RaisonSocialeJuridiction: "r", + RaisonSocialeTGI: "r", + SiretDestinataireQualif: "s", + SiretFournisseurQualif: "s", + TypeDemandePaiement: "t", + TypeFacture: "t", + TypeFactureTravaux: "t", + }, + }, + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("Factures.RechercherDemandePaiement returned %+v, want %+v", got, want) + } + + testNewRequestAndDoRequestFailure(t, "RechercherDemandePaiement", client, func() error { + _, err := client.Factures.RechercherDemandePaiement(ctx, opt) + return err + }) +} + +func TestFacturesService_RechercherFactureParRecipiendaire(t *testing.T) { + client, mux, teardown := setup() + defer teardown() + + mux.HandleFunc("/cpro/factures/v1/rechercher/recipiendaire", func(w http.ResponseWriter, r *http.Request) { + v := new(RechercherFactureRecipiendaireOptions) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) + testMethod(t, r, http.MethodPost) + w.Write([]byte(`{ + "codeRetour": 1, + "libelle": "l", + "listeFactures": [ + { + "codeDestinataire": "c", + "codeFournisseur": "c", + "codeMOA": "c", + "codeMOE": "c", + "codeServiceExecutant": "c", + "codeServiceFournisseur": "c", + "commentaireEtatCourant": "c", + "dateDepot": ` + defaultDateStr + `, + "dateFacture": ` + defaultDateStr + `, + "dateHeureEtatCourant": ` + defaultDateTimeStr + `, + "designationDestinataire": "d", + "designationFournisseur": "d", + "designationMOA": "d", + "designationMOE": "d", + "devise": "d", + "factureTelechargeeParDestinataire": true, + "idDestinataire": 1, + "idFacture": 1, + "idServiceExecutant": 1, + "montantAPayer": 1, + "montantHT": 1, + "montantTTC": 1, + "nomServiceExecutant": "n", + "nomServiceFournisseur": "n", + "numeroBonCommande": "n", + "numeroFacture": "n", + "numeroMarche": "n", + "statut": "s", + "taille": 1, + "typeDemandePaiement": "t", + "typeFacture": "t", + "typeFactureTravaux": "t", + "typeIdentifiantFournisseur": "t", + "typeIdentifiantMOA": "t", + "typeIdentifiantMOE": "t" + } + ], + "nbResultatsParPage": 1, + "pageCourante": 1, + "pages": 1, + "total": 1 + }`)) + }) + + ctx := context.Background() + opt := RechercherFactureRecipiendaireOptions{} + got, err := client.Factures.RechercherFactureParRecipiendaire(ctx, opt) + + if err != nil { + t.Errorf("Factures.RechercherFactureParRecipiendaire returned error : %v", err) + } + + want := &RechercherFactureRecipiendaireResponse{ + CodeRetour: 1, + Libelle: "l", + Factures: &[]FactureRecherche{ + { + CodeDestinataire: "c", + CodeFournisseur: "c", + CodeMOA: "c", + CodeMOE: "c", + CodeServiceExecutant: "c", + CodeServiceFournisseur: "c", + CommentaireEtatCourant: "c", + DateDepot: &Date{defaultDate}, + DateFacture: &Date{defaultDate}, + DateHeureEtatCourant: &defaultDate, + DesignationDestinataire: "d", + DesignationFournisseur: "d", + DesignationMOA: "d", + DesignationMOE: "d", + Devise: "d", + FactureTelechargeeParDestinataire: true, + IdDestinataire: 1, + IdFacture: 1, + IdServiceExecutant: 1, + MontantAPayer: 1, + MontantHT: 1, + MontantTTC: 1, + NomServiceExecutant: "n", + NomServiceFournisseur: "n", + NumeroBonCommande: "n", + NumeroFacture: "n", + NumeroMarche: "n", + Statut: "s", + Taille: 1, + TypeDemandePaiement: "t", + TypeFacture: "t", + TypeFactureTravaux: "t", + TypeIdentifiantFournisseur: "t", + TypeIdentifiantMOA: "t", + TypeIdentifiantMOE: "t", + }, + }, + NbResultatsParPage: 1, + PageCourante: 1, + Pages: 1, + Total: 1, + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("Factures.RechercherFactureParRecipiendaire returned %+v, want %+v", got, want) + } + + testNewRequestAndDoRequestFailure(t, "RechercherFactureParRecipiendaire", client, func() error { + _, err := client.Factures.RechercherFactureParRecipiendaire(ctx, opt) + return err + }) +} diff --git a/factures_traitements.go b/factures_traitements.go new file mode 100644 index 0000000..7f2173d --- /dev/null +++ b/factures_traitements.go @@ -0,0 +1,41 @@ +package choruspro + +import ( + "context" + "net/http" +) + +type TraiterFactureAValiderOptions struct { + Action ActionFacture `json:"action,omitempty"` + ComplementInfo string `json:"complementInfo,omitempty"` + IdFacture int64 `json:"idFacture,omitempty"` + IdPieceJointe int64 `json:"idPieceJointe,omitempty"` + IdValideur int64 `json:"idValideur,omitempty"` + MotifRefus string `json:"motifRefus,omitempty"` + TypeValideur string `json:"typeValideur,omitempty"` +} + +type TraiterFactureAValiderResponse struct { + CodeRetour int `json:"codeRetour,omitempty"` + DateTraitement *Date `json:"dateTraitement,omitempty"` + IdFacture int64 `json:"idFacture,omitempty"` + Libelle string `json:"libelle,omitempty"` + NumeroFacture string `json:"numeroFacture,omitempty"` + StatutFacture string `json:"statutFacture,omitempty"` +} + +func (s *FacturesService) TraiterFactureAValider(ctx context.Context, opts TraiterFactureAValiderOptions) (*TraiterFactureAValiderResponse, error) { + req, err := s.client.newRequest(ctx, http.MethodPost, "cpro/factures/v1/traiter/factureAValider", opts) + if err != nil { + return nil, err + } + + res := new(TraiterFactureAValiderResponse) + + err = s.client.doRequest(ctx, req, res) + if err != nil { + return nil, err + } + + return res, nil +} diff --git a/factures_traitements_test.go b/factures_traitements_test.go new file mode 100644 index 0000000..1e6dd6e --- /dev/null +++ b/factures_traitements_test.go @@ -0,0 +1,54 @@ +package choruspro + +import ( + "context" + "encoding/json" + "net/http" + "reflect" + "testing" +) + +func TestFacturesService_TraiterFactureAValider(t *testing.T) { + client, mux, teardown := setup() + defer teardown() + + mux.HandleFunc("/cpro/factures/v1/traiter/factureAValider", func(w http.ResponseWriter, r *http.Request) { + v := new(TraiterFactureAValiderOptions) + assertNilError(t, json.NewDecoder(r.Body).Decode(v)) + testMethod(t, r, http.MethodPost) + w.Write([]byte(`{ + "codeRetour": 1, + "dateTraitement": ` + defaultDateStr + `, + "idFacture": 1, + "libelle": "l", + "numeroFacture": "n", + "statutFacture": "s" + }`)) + }) + + ctx := context.Background() + opt := TraiterFactureAValiderOptions{} + got, err := client.Factures.TraiterFactureAValider(ctx, opt) + + if err != nil { + t.Errorf("Factures.TraiterFactureAValider returned error : %v", err) + } + + want := &TraiterFactureAValiderResponse{ + CodeRetour: 1, + DateTraitement: &Date{defaultDate}, + IdFacture: 1, + Libelle: "l", + NumeroFacture: "n", + StatutFacture: "s", + } + + if !reflect.DeepEqual(got, want) { + t.Errorf("Factures.TraiterFactureAValider returned %+v, want %+v", got, want) + } + + testNewRequestAndDoRequestFailure(t, "TraiterFactureAValider", client, func() error { + _, err := client.Factures.TraiterFactureAValider(ctx, opt) + return err + }) +} diff --git a/pagination.go b/pagination.go index aa1960b..bbea41b 100644 --- a/pagination.go +++ b/pagination.go @@ -1,15 +1,43 @@ package choruspro +type TriSens string + +const ( + TriSensAsc TriSens = "Ascendant " + TriSensDesc TriSens = "Descendant" +) + type PaginationResponse struct { - NbResultatsParPage int32 `json:"nbResultatsParPage"` - PageCourante int32 `json:"pageCourante"` - Pages int32 `json:"pages"` - Total int32 `json:"total"` + NbResultatsParPage int `json:"nbResultatsParPage"` + PageCourante int `json:"pageCourante"` + Pages int `json:"pages"` + Total int `json:"total"` } type PaginationOptions struct { - NbResultatsParPage int32 `json:"nbResultatsParPage,omitempty"` - PageResultatDemandee int32 `json:"pageResultatDemandee,omitempty"` - TriColonne string `json:"triColonne,omitempty"` - TriSens string `json:"triSense,omitempty"` + NbResultatsParPage int `json:"nbResultatsParPage,omitempty"` + PageResultatDemandee int `json:"pageResultatDemandee,omitempty"` + TriColonne string `json:"triColonne,omitempty"` + TriSens TriSens `json:"triSense,omitempty"` +} + +type PaginationLignesPosteOptions struct { + NbResultatsParPage int `json:"nbResultatsParPageLignesPoste,omitempty"` + PageResultatDemandee int `json:"pageResultatDemandeeLignesPoste,omitempty"` + TriColonne string `json:"triColonneListeLignesPoste,omitempty"` + TriSens TriSens `json:"triSensListeLignesPoste,omitempty"` +} + +type PaginationPiecesJointesOptions struct { + NbResultatsParPage int `json:"nbResultatsParPageListePieceJointe,omitempty"` + PageResultatDemandee int `json:"pageResultatDemandeeListePieceJointe,omitempty"` + TriColonne string `json:"triColonneListePiecesJointes,omitempty"` + TriSens TriSens `json:"triSensListePiecesJointes,omitempty"` +} + +type PaginationLignesRecapTVAOptions struct { + NbResultatsParPage int `json:"nbResultatsParPageListeListeRecapitulatifTVA,omitempty"` + PageResultatDemandee int `json:"pageResultatDemandeeListeRecapitulatifTVA,omitempty"` + TriColonne string `json:"triColonneListeRecapitulatifTVA,omitempty"` + TriSens TriSens `json:"triSensListeRecapitulatifTVA,omitempty"` } diff --git a/transverses.go b/transverses.go index 87dc7db..a295d6c 100644 --- a/transverses.go +++ b/transverses.go @@ -27,3 +27,10 @@ const ( SyntaxeFluxE2CiiFacturx SyntaxeFlux = "IN_DP_E2_CII_FACTURX" SyntaxeFluxE3UblInvoice SyntaxeFlux = "IN_DP_E3_UBL_INVOICE" ) + +type FormatFichier string + +const ( + FormatFichierPdf FormatFichier = "PDF" + FormatFichierPivot FormatFichier = "PIVOT" +) diff --git a/transverses_pieces_jointes.go b/transverses_pieces_jointes.go index a3f5d0a..aa50508 100644 --- a/transverses_pieces_jointes.go +++ b/transverses_pieces_jointes.go @@ -240,14 +240,12 @@ func (s *TransversesService) RechercherPiecesJointesMonCompte(ctx context.Contex type TelechargerPieceJointeDemandePaiementOptions struct { // 2 values possible : "OUI" or "NON" - AvecPJCompltementaires string `json:"avecPiecesJointesComplementaires"` - - // 2 values possible : "PDF" or "PIVOT" - Format string `json:"format"` - ListeFacture []ListeIdFacture `json:"listeFacture"` + AvecPJCompltementaires string `json:"avecPiecesJointesComplementaires"` + Format FormatFichier `json:"format"` + ListeFacture []IdFacture `json:"listeFacture"` } -type ListeIdFacture struct { +type IdFacture struct { IdFacture int64 `json:"idFacture"` } diff --git a/transverses_pieces_jointes_test.go b/transverses_pieces_jointes_test.go index 781e164..77997ea 100644 --- a/transverses_pieces_jointes_test.go +++ b/transverses_pieces_jointes_test.go @@ -425,7 +425,7 @@ func TestTransversesService_TelechargerPieceJointe_MissingOption(t *testing.T) { DemandePaiement: &TelechargerPieceJointeDemandePaiementOptions{ AvecPJCompltementaires: "OUI", Format: "PDF", - ListeFacture: []ListeIdFacture{}, + ListeFacture: []IdFacture{}, }, }, }, diff --git a/transverses_structures.go b/transverses_structures.go index 66262cc..ef9d62b 100644 --- a/transverses_structures.go +++ b/transverses_structures.go @@ -145,13 +145,13 @@ func (s *TransversesService) ConsulterInformationsSIRET(ctx context.Context, opt } type ListeDestinataires struct { - CodeRetour int32 `json:"codeRetour"` - Libelle string `json:"libelle"` - Destinataires []Destinataire `json:"listeDestinataires"` - Pagination PaginationResponse `json:"parametresRetour"` + CodeRetour int32 `json:"codeRetour"` + Libelle string `json:"libelle"` + Destinataires []DestinataireRecherche `json:"listeDestinataires"` + Pagination PaginationResponse `json:"parametresRetour"` } -type Destinataire struct { +type DestinataireRecherche struct { IdStructureCPP int64 `json:"idStructureCPP"` Siret string `json:"siret"` Nom string `json:"nomDestinataire,omitempty"` diff --git a/transverses_structures_test.go b/transverses_structures_test.go index e41e235..0af8a3a 100644 --- a/transverses_structures_test.go +++ b/transverses_structures_test.go @@ -359,7 +359,7 @@ func TestTransversesService_RechercherDestinataires(t *testing.T) { want := &ListeDestinataires{ CodeRetour: 0, Libelle: "l", - Destinataires: []Destinataire{ + Destinataires: []DestinataireRecherche{ { IdStructureCPP: 1, Siret: "s",