summaryrefslogtreecommitdiffstats
path: root/src/cepis-lookup.cob
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-27 20:39:38 -0300
committerMurilo Ijanc <[email protected]>2026-07-27 20:39:38 -0300
commit4014037e505876ed8c4df229ace3a65092e64ca8 (patch)
tree367a84c87c75df41fb7218604a3a7d0260cd6cb5 /src/cepis-lookup.cob
parentf979d07d23098b96e758b3feb555cd06d85d9b2d (diff)
downloadcobol-0.2.0.tar.gz
Expose the faixa a missing CEP would have belonged toHEADv0.2.0main
A CEP that fails is rarely a random number: it is someone who knows the city and guessed the digits, and the classic guess is the -000 that 957 municipalities never received. The API now attaches that municipality to the 404, and a caller left with nothing but "does not exist" cannot tell a typo in a real city from a CEP that was never plausible. It goes in CEPIS-STATUS, not CEPIS-ADDRESS. The call has still failed and the address is still empty; putting a localidade where the address lives would let a caller that forgets to test the status read Areal as the answer to a CEP that does not exist. Parsing is best effort throughout. faixa is omitted rather than sent as null for a band no municipality owns, so its absence is the normal case and there is a flag instead of a marker value; a block that is missing, is not an object, or is short of localidade, uf, cep_ini, cep_fim and ceps is dropped and the not-found comes back clean. Failing a 404 the caller already understands over a decoration on it would be a poor trade. cep_ini and cep_fim are the CEPs that exist, not the bounds the Correios publish, and the span between them is mostly empty -- hence ceps beside them, so the pair is not read as a list.
Diffstat (limited to 'src/cepis-lookup.cob')
-rw-r--r--src/cepis-lookup.cob135
1 files changed, 135 insertions, 0 deletions
diff --git a/src/cepis-lookup.cob b/src/cepis-lookup.cob
index cc6e412..90f1502 100644
--- a/src/cepis-lookup.cob
+++ b/src/cepis-lookup.cob
@@ -22,6 +22,13 @@ PROGRAM-ID. CEPIS-LOOKUP.
*> means the CEP is a whole municipality and the point is its centroid,
*> with a radius of 7 to 40 km. Computing shipping from the second is
*> wrong by tens of kilometres.
+*>
+*> A CEPIS-NOT-FOUND may come back with CEPIS-FAIXA filled: the
+*> municipality the CEP would have belonged to. A CEP that fails is
+*> rarely a random number -- it is usually someone who knows the city and
+*> guessed the digits, and the classic guess is the -000 that 957
+*> municipalities never received. The lookup has still failed and the
+*> address is still empty; CEPIS-FAIXA only names where the guess landed.
*> ---------------------------------------------------------------------
DATA DIVISION.
@@ -38,6 +45,17 @@ COPY "cepis-json.cpy".
01 WS-LON PIC S9(3)V9(6).
01 WS-RAIO PIC 9(9).
01 WS-PRECISAO PIC X(16).
+01 WS-FAIXA-FROM PIC 9(9).
+01 WS-FAIXA-TO PIC 9(9).
+01 WS-FAIXA-OK PIC X.
+01 WS-F-LOCALIDADE PIC X(100).
+01 WS-F-UF PIC X(2).
+01 WS-F-ESTADO PIC X(60).
+01 WS-F-REGIAO PIC X(30).
+01 WS-F-IBGE PIC X(10).
+01 WS-F-CEP-INI PIC X(8).
+01 WS-F-CEP-FIM PIC X(8).
+01 WS-F-CEPS PIC 9(9).
01 WS-I PIC 9(4).
01 WS-C PIC X.
01 WS-DOTS PIC 9(4).
@@ -82,6 +100,7 @@ MAIN-START.
STRING "CEP " WS-CEP " does not exist in the DNE database"
DELIMITED BY SIZE INTO CEPIS-STATUS-MESSAGE
END-STRING
+ PERFORM PARSE-FAIXA
WHEN 400
SET CEPIS-INVALID-CEP TO TRUE
PERFORM API-MESSAGE
@@ -133,6 +152,13 @@ GET-GEO-MEMBER.
END-CALL.
*> -------------------------------------------------------------------
+GET-FAIXA-MEMBER.
+ MOVE WS-FAIXA-FROM TO JS-FROM
+ MOVE WS-FAIXA-TO TO JS-TO
+ CALL "CEPIS-JSON-GET" USING HTTP-BODY CEPIS-JSON-SCAN
+ END-CALL.
+
+*> -------------------------------------------------------------------
PARSE-ADDRESS.
MOVE "cep" TO JS-KEY
PERFORM GET-MEMBER
@@ -290,6 +316,115 @@ PARSE-GEO.
END-IF.
*> -------------------------------------------------------------------
+*> The 404 body may name the municipality the CEP would have belonged
+*> to. It is context for the error and nothing else: the status stays
+*> CEPIS-NOT-FOUND and CEPIS-ADDRESS stays empty, because a CEP that the
+*> DNE does not have is not an address no matter which city it is near.
+*>
+*> "faixa" is omitted -- never sent as null -- when the CEP falls in a
+*> band no municipality owns, so its absence is the normal case, not an
+*> error. Everything here is therefore best effort: a faixa that is
+*> missing, is not an object, or is short of the members below is
+*> dropped, and the caller still gets a clean not-found. Turning a 404
+*> the caller already understands into CEPIS-INVALID-RESPONSE over a
+*> decoration would be a poor trade.
+*>
+*> cep_ini and cep_fim must both be eight digits and ceps must be a
+*> number, or the whole block is dropped. The span is sparse -- Areal's
+*> 118 CEPs are spread over the ~4900 numbers between 25845001 and
+*> 25849899 -- so handing a caller the pair without the count invites
+*> reading it as a list of valid CEPs, which it is not.
+PARSE-FAIXA.
+ INITIALIZE CEPIS-FAIXA
+ SET CEPIS-FAIXA-ABSENT TO TRUE
+ MOVE "faixa" TO JS-KEY
+ PERFORM GET-MEMBER
+ IF JS-TYPE NOT = "O"
+ EXIT PARAGRAPH
+ END-IF
+ MOVE JS-VSTART TO WS-FAIXA-FROM
+ MOVE JS-VEND TO WS-FAIXA-TO
+ MOVE "Y" TO WS-FAIXA-OK
+
+ MOVE "localidade" TO JS-KEY
+ PERFORM GET-FAIXA-MEMBER
+ IF JS-TYPE = "S" AND JS-VALUE-LEN > 0
+ MOVE JS-VALUE TO WS-F-LOCALIDADE
+ ELSE
+ MOVE "N" TO WS-FAIXA-OK
+ END-IF
+
+ MOVE "uf" TO JS-KEY
+ PERFORM GET-FAIXA-MEMBER
+ IF JS-TYPE = "S" AND JS-VALUE-LEN = 2
+ MOVE JS-VALUE TO WS-F-UF
+ ELSE
+ MOVE "N" TO WS-FAIXA-OK
+ END-IF
+
+ MOVE "cep_ini" TO JS-KEY
+ PERFORM GET-FAIXA-MEMBER
+ IF JS-TYPE = "S" AND JS-VALUE-LEN = 8
+ MOVE JS-VALUE TO WS-F-CEP-INI
+ ELSE
+ MOVE "N" TO WS-FAIXA-OK
+ END-IF
+
+ MOVE "cep_fim" TO JS-KEY
+ PERFORM GET-FAIXA-MEMBER
+ IF JS-TYPE = "S" AND JS-VALUE-LEN = 8
+ MOVE JS-VALUE TO WS-F-CEP-FIM
+ ELSE
+ MOVE "N" TO WS-FAIXA-OK
+ END-IF
+
+ MOVE "ceps" TO JS-KEY
+ PERFORM GET-FAIXA-MEMBER
+ PERFORM CHECK-NUMERIC
+ IF WS-NUM-OK = "Y"
+ COMPUTE WS-F-CEPS ROUNDED = FUNCTION NUMVAL (JS-VALUE)
+ ELSE
+ MOVE "N" TO WS-FAIXA-OK
+ END-IF
+
+ IF WS-FAIXA-OK NOT = "Y"
+ EXIT PARAGRAPH
+ END-IF
+
+ *> The three below are decoration: a faixa the API sends without
+ *> them still names the municipality, so they never fail the block.
+ MOVE SPACES TO WS-F-ESTADO
+ MOVE "estado" TO JS-KEY
+ PERFORM GET-FAIXA-MEMBER
+ IF JS-TYPE = "S"
+ MOVE JS-VALUE TO WS-F-ESTADO
+ END-IF
+
+ MOVE SPACES TO WS-F-REGIAO
+ MOVE "regiao" TO JS-KEY
+ PERFORM GET-FAIXA-MEMBER
+ IF JS-TYPE = "S"
+ MOVE JS-VALUE TO WS-F-REGIAO
+ END-IF
+
+ MOVE SPACES TO WS-F-IBGE
+ MOVE "ibge" TO JS-KEY
+ PERFORM GET-FAIXA-MEMBER
+ IF JS-TYPE = "S"
+ MOVE JS-VALUE TO WS-F-IBGE
+ END-IF
+
+ SET CEPIS-FAIXA-KNOWN TO TRUE
+ MOVE WS-F-LOCALIDADE TO CEPIS-FAIXA-LOCALIDADE
+ MOVE WS-F-UF TO CEPIS-FAIXA-UF
+ MOVE WS-F-ESTADO TO CEPIS-FAIXA-ESTADO
+ MOVE WS-F-REGIAO TO CEPIS-FAIXA-REGIAO
+ MOVE WS-F-IBGE TO CEPIS-FAIXA-IBGE
+ MOVE WS-F-CEP-INI TO CEPIS-FAIXA-CEP-INI
+ MOVE WS-F-CEP-FIM TO CEPIS-FAIXA-CEP-FIM
+ MOVE WS-F-CEPS TO CEPIS-FAIXA-CEPS.
+
+*> -------------------------------------------------------------------
*> FUNCTION NUMVAL answers 0 for text it cannot read, which would turn
*> "lat": "not a number" into a coordinate off the coast of Africa. The
*> text is therefore checked before it is converted.