Files
dtf-system/app/jadlog_probe.py
Cauê Faleiros 9bea187ea4
All checks were successful
Build and deploy / Validate source (push) Successful in 1m20s
Build and deploy / Integration suite on a real stack (push) Successful in 2m49s
Build and deploy / Secret scan and release gate (push) Successful in 10s
Build and deploy / Publish images (push) Successful in 1m51s
feat: add a read-only Jadlog price probe
app/jadlog.py prices one package through Jadlog's Simulador de Frete as the
API manual v2.3 describes it; app.jadlog_probe prices test weights to six
regions on the client's account to confirm token, account and contract.
Tested against a fake transport. The roadmap records the Jadlog data and the
Mercado Pago account setup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 10:41:18 -03:00

76 lines
3.2 KiB
Python

"""Read-only price check against the client's real Jadlog account, run by hand.
A quote creates no shipment and costs nothing.
python -m app.jadlog_probe [--cep 01310100 ...] [--peso 0.5 ...] [--valor 100]
Without --cep and --peso it prices a few test weights to a few regions. It
answers whether the token, CNPJ and account are accepted, whether a contract
number is required (Jadlog names it in the error), and what the contract
prices and delivery times are. The first failure stops the run: an account
problem would repeat on every line.
Locally, with the credentials in jadlog.env (ignored by git):
docker compose -f compose.local.yaml -f compose.providers.yaml run --rm --no-deps --build \\
--env-from-file jadlog.env worker python -m app.jadlog_probe
"""
import argparse
import sys
from decimal import Decimal
from .core.secrets import load as load_secret_files
from .jadlog import JadlogError, JadlogQuotes
DESTINATIONS = {'14402310': 'Franca (origem)', '01310100': 'São Paulo', '20040002': 'Rio de Janeiro',
'80010000': 'Curitiba', '50030230': 'Recife', '69005010': 'Manaus'}
WEIGHTS = ['0.3', '0.5', '1', '2', '5']
def money(cents):
return f'R$ {cents / 100:.2f}'.replace('.', ',')
def run(quotes, ceps, weights, declared_cents, out):
header = quotes.token
for weight in weights:
for cep in ceps:
try:
result = quotes.quote(cep, Decimal(weight), declared_cents)
except JadlogError as error:
# The manual shows the header as the bare token; some accounts
# are issued one that expects the Bearer scheme.
if '401' in str(error) and not header.lower().startswith('bearer '):
quotes.token = 'Bearer ' + header
header = quotes.token
try:
result = quotes.quote(cep, Decimal(weight), declared_cents)
except JadlogError as retry:
out(f'ERRO {cep} {weight} kg: {retry} (also with "Bearer ")')
return 1
out('Note: the token only works with the "Bearer " prefix.')
else:
out(f'ERRO {cep} {weight} kg: {error}')
return 1
days = result['days']
out(f"{weight} kg\t{cep}\t{DESTINATIONS.get(cep, '')}\t{money(result['total_cents'])}\t"
f"{days if days is not None else '?'} dia(s)")
return 0
def main(argv=None):
parser = argparse.ArgumentParser(prog='python -m app.jadlog_probe')
parser.add_argument('--cep', action='append', help='destination CEP (repeatable)')
parser.add_argument('--peso', action='append', help='weight in kg (repeatable)')
parser.add_argument('--valor', default='100', help='declared value in reais (default 100)')
args = parser.parse_args(argv)
load_secret_files()
quotes = JadlogQuotes()
declared = int(Decimal(args.valor) * 100)
print(f'Origem {quotes.origin}, modalidade {quotes.modalidade}, contrato {quotes.contrato or "-"}, '
f'valor declarado {money(declared)}')
return run(quotes, args.cep or list(DESTINATIONS), args.peso or WEIGHTS, declared, print)
if __name__ == '__main__':
sys.exit(main())