# Integração Jasmin no ClientFlow Esta versão adiciona a primeira integração Jasmin validada com testes reais em Jasmin 3.02. ## O que foi validado - OAuth Client Credentials: - `https://identity.primaverabss.com/connect/token` - `grant_type=client_credentials` - `scope=application` - `GET /businessCore/productInfos/getVersions` - Clientes: - `GET /salesCore/customerParties/getCustomerByCompanyTaxId/{nif}` - `POST /salesCore/customerParties` - Produtos: - `GET /salesCore/salesItems/extension/odata?$top=50` - Orçamentos: - `POST /sales/quotations` - `documentType=ORC` - `serie=ORC2026` - Faturas: - `POST /billing/invoices/fromQuotation/{quotationId}` com body `{}` ## Regras importantes descobertas 1. O NIF deve ser pesquisado no Jasmin sem prefixo `PT`. 2. O Jasmin rejeita `electronicMail` e `telephone` vazios; campos opcionais vazios são omitidos. 3. OData tem limite de `$top=100`. 4. Cliente novo pode usar `partyKey=CF{NIF}`. 5. Converter orçamento em fatura exige `json={}`; sem body pode devolver `411 Length Required`. ## Novas tabelas - `customers` - `commercial_documents` - `commercial_document_lines` - `shipments` Estas tabelas permitem o pressuposto correto: ```text Cliente → várias oportunidades → vários orçamentos → várias faturas ``` ## Fluxo na oportunidade A página da oportunidade tem dois botões simples: ```text [Criar orçamento] [Converter em fatura] ``` `Criar orçamento` faz internamente: ```text find_or_create_customer create_quotation ``` `Converter em fatura` faz internamente: ```text pegar no orçamento ativo/mais recente POST /billing/invoices/fromQuotation/{quotationId} com {} grava a fatura ligada ao orçamento local ``` ## Variáveis `.env` ```env JASMIN_ENABLED=true JASMIN_OUTBOX_ENABLED=true JASMIN_BASE_URL=https://my.jasminsoftware.com JASMIN_PUBLIC_URL=https://my.jasminsoftware.com JASMIN_TOKEN_URL=https://identity.primaverabss.com/connect/token JASMIN_SCOPE=application JASMIN_ACCOUNT=... JASMIN_SUBSCRIPTION=... JASMIN_CLIENT_ID=... JASMIN_CLIENT_SECRET=... JASMIN_COMPANY_KEY=CTULDA JASMIN_QUOTATION_TYPE=ORC JASMIN_QUOTATION_SERIE=ORC2026 JASMIN_DEFAULT_PRICE_LIST=03 JASMIN_DEFAULT_PAYMENT_METHOD=TRA JASMIN_DEFAULT_PAYMENT_TERM=00 JASMIN_DEFAULT_DELIVERY_TERM=TRANSP JASMIN_DEFAULT_CURRENCY=EUR JASMIN_DEFAULT_COUNTRY=PT JASMIN_DEFAULT_CUSTOMER_GROUP=02 JASMIN_DEFAULT_PARTY_TAX_SCHEMA=CONTINENTE JASMIN_DEFAULT_UNIT=UN JASMIN_DEFAULT_ITEM_TAX_SCHEMA=NORMAL JASMIN_DEFAULT_SALES_ITEM=CARREGADOR_MONO_7KW ``` ## Teste não destrutivo ```bash python scripts/test_jasmin_connection.py ``` ## Processar outbox Jasmin Modo seguro: ```bash OUTBOX_TARGET_SYSTEM=jasmin JASMIN_OUTBOX_ENABLED=true OUTBOX_DRY_RUN=true python scripts/process_outbox.py ``` Modo real: ```bash OUTBOX_TARGET_SYSTEM=jasmin JASMIN_OUTBOX_ENABLED=true OUTBOX_DRY_RUN=false python scripts/process_outbox.py ``` ## Dados necessários na oportunidade Para criar cliente Jasmin novo, a oportunidade precisa de: - nome do cliente - NIF em `metadata.customer_tax_id`, `metadata.nif` ou `metadata.customer.tax_id` - morada/código postal/cidade se disponível Para criar orçamento, as linhas da oportunidade precisam de mapear para artigos Jasmin. O serviço usa por ordem: 1. `opportunity_items.metadata.jasmin_sales_item` 2. `opportunity_items.metadata.jasmin_item_key` 3. `opportunity_items.sku` 4. `JASMIN_DEFAULT_SALES_ITEM`