github.com/mundipagg/boleto-api@v0.0.0-20230620145841-3f9ec742599f/caixa/caixa_test.go (about) 1 package caixa 2 3 import ( 4 "fmt" 5 "testing" 6 "time" 7 8 "github.com/PMoneda/flow" 9 "github.com/mundipagg/boleto-api/mock" 10 "github.com/mundipagg/boleto-api/models" 11 "github.com/mundipagg/boleto-api/test" 12 "github.com/mundipagg/boleto-api/tmpl" 13 "github.com/mundipagg/boleto-api/validations" 14 "github.com/stretchr/testify/assert" 15 ) 16 17 var boletoTypeParameters = []test.Parameter{ 18 {Input: models.Title{BoletoType: ""}, Expected: "99"}, 19 {Input: models.Title{BoletoType: "NSA"}, Expected: "99"}, 20 {Input: models.Title{BoletoType: "BDP"}, Expected: "99"}, 21 } 22 23 var boletoBuyerNameParameters = []test.Parameter{ 24 {Input: "Leonardo Jasmim", Expected: "<NOME>Leonardo Jasmim</NOME>"}, 25 {Input: "Ântôníõ Tùpìnâmbáú", Expected: "<NOME>Antonio Tupinambau</NOME>"}, 26 {Input: "Accepted , / ( ) * = - + ! : ? . ; _ ' ", Expected: "<NOME>Accepted , / ( ) * = - + ! : ? . ; _ ' </NOME>"}, 27 {Input: "NotAccepted @#$%¨{}[]^~\"&<>\\", Expected: "<NOME>NotAccepted </NOME>"}, 28 } 29 30 var boletoInstructionsParameters = []test.Parameter{ 31 {Input: ", / ( ) * = - + ! : ? . ; _ ' ", Expected: "<MENSAGEM>, / ( ) * = - + ! : ? . ; _ ' </MENSAGEM>"}, 32 {Input: "@ # $ % ¨ { } [ ] ^ ~ \" & < > \\", Expected: " "}, 33 } 34 35 var boletoCepParameters = []test.Parameter{ 36 {Input: "12345-123", Expected: "<CEP>12345123</CEP>"}, 37 {Input: "01000-000", Expected: "<CEP>01000000</CEP>"}, 38 {Input: "08000-123", Expected: "<CEP>08000123</CEP>"}, 39 {Input: "5000-098", Expected: "<CEP>5000098</CEP>"}, 40 {Input: "98765-456", Expected: "<CEP>98765456</CEP>"}, 41 } 42 43 var interestPercentageParameters = []test.Parameter{ 44 {Input: models.Interest{DaysAfterExpirationDate: 1, AmountPerDayInCents: 0, PercentagePerMonth: 3.27}}, 45 {Input: models.Interest{DaysAfterExpirationDate: 1, AmountPerDayInCents: 0, PercentagePerMonth: 4.238}}, 46 } 47 48 func TestProcessBoleto_WhenServiceRespondsSuccessfully_ShouldHasSuccessfulBoletoResponse(t *testing.T) { 49 mock.StartMockService("9018") 50 51 input := newStubBoletoRequestCaixa().Build() 52 bank := New() 53 54 output, _ := bank.ProcessBoleto(input) 55 56 test.AssertProcessBoletoWithSuccess(t, output) 57 } 58 59 func TestProcessBoleto_WhenServiceRespondsFailed_ShouldHasFailedBoletoResponse(t *testing.T) { 60 mock.StartMockService("9017") 61 62 input := newStubBoletoRequestCaixa().WithAmountInCents(400).Build() 63 bank := New() 64 65 output, _ := bank.ProcessBoleto(input) 66 67 test.AssertProcessBoletoFailed(t, output) 68 } 69 70 func TestProcessBoleto_WhenRequestContainsInvalidOurNumberParameter_ShouldHasFailedBoletoResponse(t *testing.T) { 71 largeOurNumber := uint(9999999999999999) 72 mock.StartMockService("9016") 73 74 input := newStubBoletoRequestCaixa().WithOurNumber(largeOurNumber).Build() 75 76 bank := New() 77 78 output, _ := bank.ProcessBoleto(input) 79 80 test.AssertProcessBoletoFailed(t, output) 81 } 82 83 func TestGetCaixaCheckSumInfo(t *testing.T) { 84 const expectedSumCode = "0200656000000000000000003008201700000000000100000732159000109" 85 const expectedToken = "LvWr1op5Ayibn6jsCQ3/2bW4KwThVAlLK5ftxABlq20=" 86 87 bank := New() 88 agreement := uint(200656) 89 expiredAt := time.Date(2017, 8, 30, 12, 12, 12, 12, time.Local) 90 doc := "00732159000109" 91 92 s := newStubBoletoRequestCaixa() 93 s.WithAgreementNumber(agreement).WithOurNumber(0).WithAmountInCents(1000) 94 s.WithExpirationDate(expiredAt).WithRecipientDocumentNumber(doc) 95 96 input := s.Build() 97 98 assert.Equal(t, expectedSumCode, bank.getCheckSumCode(*input), "Deve-se formar uma string seguindo o padrão da documentação") 99 assert.Equal(t, expectedToken, bank.getAuthToken(bank.getCheckSumCode(*input)), "Deve-se fazer um hash sha256 e encodar com base64") 100 } 101 102 func TestShouldCalculateAccountDigitCaixa(t *testing.T) { 103 input := newStubBoletoRequestCaixa().WithAgreementAccount("100000448").WithAgreementAgency("2004").Build() 104 105 assert.Nil(t, caixaValidateAccountAndDigit(input)) 106 assert.Nil(t, caixaValidateAgency(input)) 107 } 108 109 func TestGetBoletoType_WhenCalled_ShouldBeMapTypeSuccessful(t *testing.T) { 110 request := new(models.BoletoRequest) 111 for _, fact := range boletoTypeParameters { 112 request.Title = fact.Input.(models.Title) 113 _, result := getBoletoType(request) 114 assert.Equal(t, fact.Expected, result, "Deve mapear o boleto type corretamente") 115 } 116 } 117 118 func TestTemplateRequestCaixa_CEP_ParseSuccessful(t *testing.T) { 119 f := flow.NewFlow() 120 s := newStubBoletoRequestCaixa() 121 122 for _, fact := range boletoCepParameters { 123 request := s.WithBuyerZipCode(fact.Input.(string)).Build() 124 result := fmt.Sprintf("%v", f.From("message://?source=inline", request, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 125 assert.Contains(t, result, fact.Expected, "Conversão não realizada como esperado") 126 } 127 } 128 129 func TestTemplateRequestCaixa_BuyerName_ParseSuccessful(t *testing.T) { 130 f := flow.NewFlow() 131 s := newStubBoletoRequestCaixa() 132 133 for _, fact := range boletoBuyerNameParameters { 134 request := s.WithBuyerName(fact.Input.(string)).Build() 135 result := fmt.Sprintf("%v", f.From("message://?source=inline", request, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 136 assert.Contains(t, result, fact.Expected, "Conversão não realizada como esperado") 137 } 138 } 139 140 func TestTemplateRequestCaixa_Instructions_ParseSuccessful(t *testing.T) { 141 f := flow.NewFlow() 142 s := newStubBoletoRequestCaixa() 143 144 for _, fact := range boletoInstructionsParameters { 145 request := s.WithInstructions(fact.Input.(string)).Build() 146 result := fmt.Sprintf("%v", f.From("message://?source=inline", request, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 147 assert.Contains(t, result, fact.Expected, "Conversão não realizada como esperado") 148 } 149 } 150 151 func TestTemplateRequestCaixa_WhenRequestV1_ParseSuccessful(t *testing.T) { 152 f := flow.NewFlow() 153 input := newStubBoletoRequestCaixa().WithBuyerAddress().Build() 154 155 b := fmt.Sprintf("%v", f.From("message://?source=inline", input, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 156 157 for _, expected := range expectedBasicTitleRequestFields { 158 assert.Contains(t, b, expected, "Erro no mapeamento dos campos básicos do Título") 159 } 160 161 for _, expected := range expectedBuyerRequestFields { 162 assert.Contains(t, b, expected, "Erro no mapeamento dos campos básicos do Comprador") 163 } 164 165 for _, notExpected := range expectedStrictRulesFieldsV2 { 166 assert.NotContains(t, b, notExpected, "Não devem haver campos de regras de pagamento na V1") 167 } 168 169 for _, notExpected := range expectedFlexRulesFieldsV2 { 170 assert.NotContains(t, b, notExpected, "Não devem haver campos de regras de pagamento na V1") 171 } 172 } 173 174 func TestTemplateRequestCaixa_WhenRequestWithStrictRulesV2_ParseSuccessful(t *testing.T) { 175 f := flow.NewFlow() 176 input := newStubBoletoRequestCaixa().WithBuyerAddress().WithStrictRules().Build() 177 178 b := fmt.Sprintf("%v", f.From("message://?source=inline", input, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 179 180 for _, expected := range expectedBasicTitleRequestFields { 181 assert.Contains(t, b, expected, "Erro no mapeamento dos campos básicos do Título") 182 } 183 184 for _, expected := range expectedBuyerRequestFields { 185 assert.Contains(t, b, expected, "Erro no mapeamento dos campos básicos do Comprador") 186 } 187 188 for _, expected := range expectedStrictRulesFieldsV2 { 189 assert.Contains(t, b, expected, "Erro no mapeamento das regras de pagamento") 190 } 191 } 192 193 func TestTemplateRequestCaixa_WhenRequestWithFlexRulesV2_ParseSuccessful(t *testing.T) { 194 f := flow.NewFlow() 195 input := newStubBoletoRequestCaixa().WithBuyerAddress().WithFlexRules().Build() 196 197 b := fmt.Sprintf("%v", f.From("message://?source=inline", input, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 198 199 for _, expected := range expectedBasicTitleRequestFields { 200 assert.Contains(t, b, expected, "Erro no mapeamento dos campos básicos do Título") 201 } 202 203 for _, expected := range expectedBuyerRequestFields { 204 assert.Contains(t, b, expected, "Erro no mapeamento dos campos básicos do Comprador") 205 } 206 207 for _, expected := range expectedFlexRulesFieldsV2 { 208 assert.Contains(t, b, expected, "Erro no mapeamento das regras de pagamento") 209 } 210 } 211 212 func TestTemplateRequestCaixa_NumberOfDaysAfterExpirationEqualsOne_NumberOfDaysAfterExpirationIsRight(t *testing.T) { 213 flow := flow.NewFlow() 214 caixaRequestStub := newStubBoletoRequestCaixa() 215 216 request := caixaRequestStub.WithStrictRules().Build() 217 result := fmt.Sprintf("%v", flow.From("message://?source=inline", request, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 218 assert.Contains(t, result, "<NUMERO_DIAS>0</NUMERO_DIAS>", "Falha ao encontrar o campo <NUMERO_DIAS>0<NUMERO_DIAS> no request") 219 } 220 221 func TestTemplateRequestCaixa_WhenRequestWithFineAndAmountInCents_ParseSuccessful(t *testing.T) { 222 f := flow.NewFlow() 223 input := newStubBoletoRequestCaixa().WithFine(1, 200, 0).Build() 224 dateExpected := input.Title.ExpireDateTime.Format("2006-01-02") 225 226 b := fmt.Sprintf("%v", f.From("message://?source=inline", input, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 227 228 assert.Contains(t, b, "<MULTA>", "Erro no mapeamento dos campos básicos do multa - <MULTA>") 229 assert.Contains(t, b, fmt.Sprintf("<DATA>%s</DATA>", dateExpected), "Erro no mapeamento dos campos básicos do multa - <DATA>") 230 assert.Contains(t, b, "<VALOR>2.00</VALOR>", "Erro no mapeamento dos campos básicos do multa - <VALOR>") 231 assert.Contains(t, b, "</MULTA>", "Erro no mapeamento dos campos básicos do multa - </MULTA>") 232 } 233 234 func TestTemplateRequestCaixa_WhenRequestWithFineAndPercentageOnTotal_ParseSuccessful(t *testing.T) { 235 f := flow.NewFlow() 236 input := newStubBoletoRequestCaixa().WithFine(1, 0, 1.3).Build() 237 dateExpected := input.Title.ExpireDateTime.Format("2006-01-02") 238 239 b := fmt.Sprintf("%v", f.From("message://?source=inline", input, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 240 241 assert.Contains(t, b, "<MULTA>", "Erro no mapeamento dos campos básicos do multa - <MULTA>") 242 assert.Contains(t, b, fmt.Sprintf("<DATA>%s</DATA>", dateExpected), "Erro no mapeamento dos campos básicos do multa - <DATA>") 243 assert.Contains(t, b, "<PERCENTUAL>1.30</PERCENTUAL>", "Erro no mapeamento dos campos básicos do multa - <VALOR>") 244 assert.Contains(t, b, "</MULTA>", "Erro no mapeamento dos campos básicos do multa - </MULTA>") 245 } 246 247 func TestTemplateRequestCaixa_WhenRequestWithInterestAndTypeIsento_ParseSuccessful(t *testing.T) { 248 f := flow.NewFlow() 249 input := newStubBoletoRequestCaixa().Build() 250 251 b := fmt.Sprintf("%v", f.From("message://?source=inline", input, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 252 253 assert.Contains(t, b, "<TIPO>ISENTO</TIPO>", "Erro no mapeamento dos campos básicos de juros - <TIPO>") 254 assert.Contains(t, b, "<VALOR>0</VALOR>", "Erro no mapeamento dos campos básicos de juros - <VALOR>") 255 } 256 257 func TestTemplateRequestCaixa_WhenRequestWithInterestAndAmountPerDayInCents_ParseSuccessful(t *testing.T) { 258 f := flow.NewFlow() 259 input := newStubBoletoRequestCaixa().WithInterest(1, 300, 0).Build() 260 daysToAdd := input.Title.Fees.Interest.DaysAfterExpirationDate 261 dateExpected := input.Title.ExpireDateTime.UTC().Add(day * time.Duration(daysToAdd)).Format("2006-01-02") 262 263 b := fmt.Sprintf("%v", f.From("message://?source=inline", input, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 264 265 assert.Contains(t, b, "<TIPO>VALOR_POR_DIA</TIPO>", "Erro no mapeamento dos campos básicos de juros - <TIPO>") 266 assert.Contains(t, b, fmt.Sprintf("<DATA>%s</DATA>", dateExpected), "Erro no mapeamento dos campos básicos de juros - <DATA>") 267 assert.Contains(t, b, "<VALOR>3.00</VALOR>", "Erro no mapeamento dos campos básicos de juros - <VALOR>") 268 } 269 270 func TestTemplateRequestCaixa_WhenRequestWithInterestAndPercentagePerMonth_ParseSuccessful(t *testing.T) { 271 f := flow.NewFlow() 272 stub := newStubBoletoRequestCaixa() 273 274 for _, fact := range interestPercentageParameters { 275 interest := fact.Input.(models.Interest) 276 request := stub.WithInterest(interest.DaysAfterExpirationDate, interest.AmountPerDayInCents, interest.PercentagePerMonth).Build() 277 daysToAdd := request.Title.Fees.Interest.DaysAfterExpirationDate 278 dateExpected := request.Title.ExpireDateTime.UTC().Add(day * time.Duration(daysToAdd)).Format("2006-01-02") 279 percentualExpected := fmt.Sprintf("%.2f", request.Title.Fees.Interest.PercentagePerMonth) 280 281 b := fmt.Sprintf("%v", f.From("message://?source=inline", request, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 282 283 assert.Contains(t, b, "<TIPO>TAXA_MENSAL</TIPO>", "Erro no mapeamento dos campos básicos de juros - <TIPO>") 284 assert.Contains(t, b, fmt.Sprintf("<DATA>%s</DATA>", dateExpected), "Erro no mapeamento dos campos básicos de juros - <DATA>") 285 assert.Contains(t, b, fmt.Sprintf("<PERCENTUAL>%s</PERCENTUAL>", percentualExpected), "Erro no mapeamento dos campos básicos de juros - <VALOR>") 286 } 287 } 288 289 func TestCaixaValidateFine(t *testing.T) { 290 input := newStubBoletoRequestCaixa().WithFine(1, 200, 0).Build() 291 292 assert.Nil(t, validations.ValidateFine(input)) 293 } 294 295 func TestCaixaValidateFineWithNilFees(t *testing.T) { 296 input := newStubBoletoRequestCaixa().Build() 297 298 assert.Nil(t, validations.ValidateFine(input)) 299 } 300 301 func TestCaixaValidateInterest(t *testing.T) { 302 input := newStubBoletoRequestCaixa().WithInterest(1, 0, 10.2).Build() 303 304 assert.Nil(t, validations.ValidateInterest(input)) 305 } 306 307 func TestCaixaValidateInterestWithNilFees(t *testing.T) { 308 input := newStubBoletoRequestCaixa().Build() 309 310 assert.Nil(t, validations.ValidateInterest(input)) 311 } 312 313 func TestTemplateRequestCaixa_WhenRequestWithPayeeGuarantorIsCNPJ_ParseSuccessful(t *testing.T) { 314 f := flow.NewFlow() 315 input := newStubBoletoRequestCaixa().WithPayeeGuarantorName("PayeeGuarantor Test Name").WithPayeeGuarantorDocumentType("CNPJ").Build() 316 317 b := fmt.Sprintf("%v", f.From("message://?source=inline", input, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 318 nodeContent := test.GetNode(b, "SACADOR_AVALISTA") 319 320 assert.Contains(t, nodeContent, "<RAZAO_SOCIAL>PayeeGuarantor Test Name</RAZAO_SOCIAL>", "Erro no mapeamento do campo name do PayeeGuarantor") 321 assert.Contains(t, nodeContent, fmt.Sprintf("<CNPJ>%s</CNPJ>", input.PayeeGuarantor.Document.Number), "Erro no mapeamento do document type do PayeeGuarantor") 322 } 323 324 func TestTemplateRequestCaixa_WhenRequestWithPayeeGuarantorIsCPF_ParseSuccessful(t *testing.T) { 325 f := flow.NewFlow() 326 input := newStubBoletoRequestCaixa().WithPayeeGuarantorName("PayeeGuarantor Test Name").WithPayeeGuarantorDocumentType("CPF").Build() 327 328 b := fmt.Sprintf("%v", f.From("message://?source=inline", input, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 329 nodeContent := test.GetNode(b, "SACADOR_AVALISTA") 330 331 assert.Contains(t, nodeContent, "<NOME>PayeeGuarantor Test Name</NOME>", "Erro no mapeamento do campo name do PayeeGuarantor") 332 assert.Contains(t, nodeContent, fmt.Sprintf("<CPF>%s</CPF>", input.PayeeGuarantor.Document.Number), "Erro no mapeamento do document type do PayeeGuarantor") 333 } 334 335 func TestTemplateRequestCaixa_WhenRequestWithPayeeGuarantorIsCPF_ParseFailed(t *testing.T) { 336 f := flow.NewFlow() 337 input := newStubBoletoRequestCaixa().WithPayeeGuarantorName("PayeeGuarantor Test Name").WithPayeeGuarantorDocumentType("CNPJ").Build() 338 339 b := fmt.Sprintf("%v", f.From("message://?source=inline", input, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 340 nodeContent := test.GetNode(b, "SACADOR_AVALISTA") 341 342 assert.NotContains(t, nodeContent, "<NOME>PayeeGuarantor Test Name</NOME>", "Erro no mapeamento do campo PayeeGuarantor") 343 assert.NotContains(t, nodeContent, fmt.Sprintf("<CPF>%s</CPF>", input.PayeeGuarantor.Document.Number), "Erro no mapeamento do document type do PayeeGuarantor") 344 } 345 346 func TestTemplateRequestCaixa_WhenRequestWithPayeeGuarantorIsCNPJ_ParseFailed(t *testing.T) { 347 f := flow.NewFlow() 348 input := newStubBoletoRequestCaixa().WithPayeeGuarantorName("PayeeGuarantor Test Name").WithPayeeGuarantorDocumentType("CPF").Build() 349 350 b := fmt.Sprintf("%v", f.From("message://?source=inline", input, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 351 nodeContent := test.GetNode(b, "SACADOR_AVALISTA") 352 353 assert.NotContains(t, nodeContent, "<RAZAO_SOCIAL>PayeeGuarantor Test Name</RAZAO_SOCIAL>", "Erro no mapeamento do campo PayeeGuarantor") 354 assert.NotContains(t, nodeContent, fmt.Sprintf("<CNPJ>%s</CNPJ>", input.PayeeGuarantor.Document.Number), "Erro no mapeamento do document type do PayeeGuarantor") 355 } 356 357 func TestTemplateRequestCaixa_WhenRequestWithPayeeGuarantorDocumentInNotValidCPF_ParseFailed(t *testing.T) { 358 mock.StartMockService("9020") 359 cnpjDocument := "00732159000109" 360 361 input := newStubBoletoRequestCaixa().WithPayeeGuarantorName("PayeeGuarantor Test Name").WithPayeeGuarantorDocumentNumber(cnpjDocument).WithPayeeGuarantorDocumentType("CPF").Build() 362 363 bank := New() 364 365 output, _ := bank.ProcessBoleto(input) 366 367 test.AssertProcessBoletoFailed(t, output) 368 } 369 370 func TestTemplateRequestCaixa_WhenRequestWithPayeeGuarantorDocumentInNotValidCNPJ_ParseFailed(t *testing.T) { 371 mock.StartMockService("9019") 372 cpfDocument := "08013156036" 373 374 input := newStubBoletoRequestCaixa().WithPayeeGuarantorName("PayeeGuarantor Test Name").WithPayeeGuarantorDocumentNumber(cpfDocument).WithPayeeGuarantorDocumentType("CNPJ").Build() 375 376 bank := New() 377 378 output, _ := bank.ProcessBoleto(input) 379 380 test.AssertProcessBoletoFailed(t, output) 381 } 382 383 func TestTemplateRequestCaixa_WhenRequestWithoutPayeeGuarantor_HasNotPayeeGuarantorNode(t *testing.T) { 384 f := flow.NewFlow() 385 input := newStubBoletoRequestCaixa().Build() 386 387 b := fmt.Sprintf("%v", f.From("message://?source=inline", input, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 388 nodeContent := test.GetNode(b, "SACADOR_AVALISTA") 389 390 assert.Contains(t, nodeContent, "", "Não deve haver o nó PayeeGuarantor") 391 } 392 393 func TestTemplateRequestCaixa_WhenRequestWithoutBuyerAddress_HasNotBuyerAddressNode(t *testing.T) { 394 f := flow.NewFlow() 395 input := newStubBoletoRequestCaixa().Build() 396 397 b := fmt.Sprintf("%v", f.From("message://?source=inline", input, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 398 nodeContent := test.GetNode(b, "ENDERECO") 399 400 assert.Empty(t, nodeContent, "Não deve haver o nó Address no Buyer") 401 } 402 403 func TestTemplateRequestCaixa_WhenRequestWithBuyerAddress_HasBuyerAddressNode(t *testing.T) { 404 f := flow.NewFlow() 405 input := newStubBoletoRequestCaixa().WithBuyerAddress().Build() 406 407 b := fmt.Sprintf("%v", f.From("message://?source=inline", input, getRequestCaixa(), tmpl.GetFuncMaps()).GetBody()) 408 nodeContent := test.GetNode(b, "ENDERECO") 409 410 assert.NotEmpty(t, nodeContent, "Deve haver o nó Address no Buyer") 411 }