35 Commits

Author SHA1 Message Date
Gitea Action
e31226b46a chore: update image tag to 3aa9673 [skip ci] 2026-02-18 16:32:39 +00:00
Luis Eduardo Estevao
3aa967352f Merge branch 'main' of https://git.simplifiquehc.com.br/simplifique/Vendaweb-api
All checks were successful
Build (develop) / Promote (main) / build-and-push-deploy (push) Successful in 1m17s
2026-02-18 13:31:09 -03:00
Luis Eduardo Estevao
175a1b9ccd feat: add ShippingService with methods for retrieving customer shippings, shop collections, customer collections, and delivery schedules. 2026-02-18 13:31:03 -03:00
Gitea Action
5665c4e71d chore: update image tag to c088c38 [skip ci] 2026-02-12 21:10:06 +00:00
c088c38a05 chore: update registry and repository URLs to use internal IP address
All checks were successful
Build (develop) / Promote (main) / build-and-push-deploy (push) Successful in 1m38s
2026-02-12 18:08:05 -03:00
d6d70400ac Merge branch 'main' of http://172.35.0.216:3000/simplifique/Vendaweb-api
Some checks failed
Build (develop) / Promote (main) / build-and-push-deploy (push) Has been cancelled
2026-02-12 18:00:14 -03:00
599a916257 fix: update health check status message to reflect new version 2026-02-12 17:36:55 -03:00
Gitea Action
fa7f05e47b chore: update image tag to e2a36da [skip ci] 2026-02-12 20:34:35 +00:00
Luis Eduardo Estevao
e2a36da1b8 Merge branch 'main' of https://git.simplifiquehc.com.br/simplifique/Vendaweb-api
All checks were successful
Build (develop) / Promote (main) / build-and-push-deploy (push) Successful in 1m22s
2026-02-12 12:59:14 -03:00
Luis Eduardo Estevao
7785f0d0b0 feat: implement sales service with product retrieval and filtering capabilities 2026-02-12 12:59:08 -03:00
Gitea Action
caba86fe3a chore: update image tag to 03519ae [skip ci] 2026-02-11 18:35:37 +00:00
Luis Eduardo Estevao
03519ae299 Merge branch 'main' of https://git.simplifiquehc.com.br/simplifique/Vendaweb-api
All checks were successful
Build (develop) / Promote (main) / build-and-push-deploy (push) Successful in 1m24s
2026-02-11 15:28:13 -03:00
Luis Eduardo Estevao
33f0271a0e feat: implement order creation and cancellation functionality with new entities for city, sales order items, and temporary order items. 2026-02-11 15:28:05 -03:00
Gitea Action
bd47e51262 chore: update image tag to f0ef3dd [skip ci] 2026-02-11 13:52:19 +00:00
Luis Eduardo Estevao
f0ef3dd21c feat: Add new sales and shopping cart management module.
All checks were successful
Build (develop) / Promote (main) / build-and-push-deploy (push) Successful in 1m45s
2026-02-11 10:49:17 -03:00
Gitea Action
f2b2572a35 chore: update image tag to e5dc346 [skip ci] 2026-01-29 23:02:51 +00:00
e5dc346b96 fix: persist shipping fee and refresh k8s docs
All checks were successful
Build (develop) / Promote (main) / build-and-push-deploy (push) Successful in 1m14s
2026-01-29 19:54:47 -03:00
Gitea Action
16882046cf chore: update image tag to fd17be5 [skip ci] 2026-01-29 18:23:08 +00:00
fd17be5408 fix: harden GitOps deploy and rollback
All checks were successful
Build (develop) / Promote (main) / build-and-push-deploy (push) Successful in 1m22s
2026-01-29 15:21:09 -03:00
Gitea Action
ecd298442b chore: update image tag to 589fa29 [skip ci] 2026-01-29 17:59:46 +00:00
589fa2913c fix: correct pipeline to update k8s manifest
All checks were successful
Build (develop) / Promote (main) / build-and-push-deploy (push) Successful in 1m21s
2026-01-29 14:58:20 -03:00
587d097d9b ci: restrict workflow triggers to main branch only
Some checks failed
Build (develop) / Promote (main) / build-and-push-deploy (push) Failing after 1m15s
2026-01-29 14:52:27 -03:00
a694af97c6 feat: add app controller with version and health check endpoints
All checks were successful
Build (develop) / Promote (main) / build-and-push-deploy (push) Successful in 1m33s
2026-01-29 14:48:57 -03:00
6523c5f520 feat: Add API endpoints for application version and health checks.
All checks were successful
Build (develop) / Promote (main) / build-and-push-deploy (push) Successful in 1m21s
2026-01-29 14:31:33 -03:00
0c09ee795e feat: migrate registry to gitea and simplify workflow
All checks were successful
Build (develop) / Promote (main) / build-and-push-deploy (push) Successful in 1m24s
2026-01-29 14:23:24 -03:00
09396e334d feat: migrate registry to gitea and simplify workflow
All checks were successful
Build (develop) / Promote (main) / build-and-push-deploy (push) Successful in 1m25s
2026-01-29 14:20:09 -03:00
605d68b4b0 feat: migrate registry to gitea and simplify workflow
All checks were successful
Build (develop) / Promote (main) / build-and-push-deploy (push) Successful in 7m16s
2026-01-29 14:06:35 -03:00
c707d4a065 feat: migrate registry to gitea and simplify workflow
Some checks failed
Build (develop) / Promote (main) / build-and-push-deploy (push) Has been cancelled
2026-01-29 13:50:01 -03:00
0b28379145 feat: migrate registry to gitea and simplify workflow
Some checks failed
Build (develop) / Promote (main) / build-and-push-deploy (push) Failing after 6s
2026-01-29 13:47:26 -03:00
ca43de8756 fix: use harbor domain instead of ip to fix ssl error
Some checks failed
Build (develop) / Promote (main) / build-and-push-deploy (push) Failing after 20s
2026-01-29 13:31:20 -03:00
bb21ca33e4 fix: update registry url to oci.simplifiquehc.com.br
Some checks failed
Build (develop) / Promote (main) / build-and-push-deploy (push) Failing after 22s
2026-01-29 13:26:13 -03:00
48d6e64ada fix: update registry url to oci.simplifiquehc.com.br
Some checks failed
Build (develop) / Promote (main) / build-and-push-deploy (push) Failing after 24s
2026-01-29 13:24:58 -03:00
e0731db836 fix: update registry url to oci.simplifiquehc.com.br
Some checks failed
Build (develop) / Promote (main) / build-and-push-deploy (push) Failing after 34s
2026-01-29 13:17:15 -03:00
d2265390bd chore: organize project and update service
Some checks failed
Build (develop) / Promote (main) / build-and-push-deploy (push) Failing after 23s
2026-01-29 12:55:15 -03:00
a34c7c415c fix: update workflow to support homolog branch
Some checks failed
Build (develop) / Promote (main) / build-and-push-deploy (push) Failing after 25s
2026-01-29 12:50:47 -03:00
21 changed files with 629 additions and 541 deletions

View File

@@ -1,7 +1,7 @@
name: Build (develop) / Promote (main)
on:
push:
branches: [main, develop, homolog]
branches: [main]
jobs:
build-and-push-deploy:
@@ -12,109 +12,30 @@ jobs:
with:
fetch-depth: 0
- name: Free disk space
- name: Build and Push
run: |
df -h
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc || true
sudo apt-get clean || true
docker system prune -af --volumes || true
df -h
- name: Build (develop) / Promote (main)
env:
REGISTRY: harbor.jurunense.com
DEV_PROJECT: vendaweb-dev
PROD_PROJECT: vendaweb-prod
IMAGE_REPO: vendaweb-api
PROMOTE_LEGACY: 'false'
HARBOR_USERNAME: ${{ secrets.HARBOR_USERNAME }}
HARBOR_PASSWORD: ${{ secrets.HARBOR_PASSWORD }}
HARBOR_DEV_USERNAME: ${{ secrets.HARBOR_DEV_USERNAME }}
HARBOR_DEV_PASSWORD: ${{ secrets.HARBOR_DEV_PASSWORD }}
HARBOR_PROD_USERNAME: ${{ secrets.HARBOR_PROD_USERNAME }}
HARBOR_PROD_PASSWORD: ${{ secrets.HARBOR_PROD_PASSWORD }}
HARBOR_LEGACY_USERNAME: ${{ secrets.HARBOR_LEGACY_USERNAME }}
HARBOR_LEGACY_PASSWORD: ${{ secrets.HARBOR_LEGACY_PASSWORD }}
REGISTRY="172.35.0.216:3000"
IMAGE_NAME="$REGISTRY/simplifique/vendaweb-api"
SHA_TAG=$(echo ${{ gitea.sha }} | cut -c1-7)
echo "${{ secrets.K8S }}" | docker login "$REGISTRY" -u "${{ gitea.actor }}" --password-stdin
docker build -t "$IMAGE_NAME:$SHA_TAG" -t "$IMAGE_NAME:latest" .
docker push "$IMAGE_NAME:$SHA_TAG"
docker push "$IMAGE_NAME:latest"
- name: Update Manifest and Push to Git
run: |
set -euo pipefail
SHA_TAG=$(echo ${{ gitea.sha }} | cut -c1-7)
IMAGE_NAME="172.35.0.216:3000/simplifique/vendaweb-api"
BRANCH="${GITHUB_REF_NAME:-${GITEA_REF_NAME:-}}"
if [ -z "$BRANCH" ] && [ -n "${GITHUB_REF:-}" ]; then
BRANCH="${GITHUB_REF#refs/heads/}"
fi
MANIFEST_FILE="k8s/overlays/prod/deployment-image-digest-patch.yaml"
DEV_IMAGE="$REGISTRY/$DEV_PROJECT/$IMAGE_REPO"
PROD_IMAGE="$REGISTRY/$PROD_PROJECT/$IMAGE_REPO"
LEGACY_IMAGE="$REGISTRY/library/$IMAGE_REPO"
sed -i "s|image: $IMAGE_NAME:.*|image: $IMAGE_NAME:$SHA_TAG|g" "$MANIFEST_FILE"
DEV_USER="${HARBOR_DEV_USERNAME:-$HARBOR_USERNAME}"
DEV_PASS="${HARBOR_DEV_PASSWORD:-$HARBOR_PASSWORD}"
PROD_USER="${HARBOR_PROD_USERNAME:-$HARBOR_USERNAME}"
PROD_PASS="${HARBOR_PROD_PASSWORD:-$HARBOR_PASSWORD}"
LEGACY_USER="${HARBOR_LEGACY_USERNAME:-$PROD_USER}"
LEGACY_PASS="${HARBOR_LEGACY_PASSWORD:-$PROD_PASS}"
git config user.name "Gitea Action"
git config user.email "actions@simplifiquehc.com.br"
if [ "$BRANCH" = "develop" ]; then
TAG=$(echo ${{ gitea.sha }} | cut -c1-7)
echo "$DEV_PASS" | docker login "$REGISTRY" -u "$DEV_USER" --password-stdin
docker build -t "$DEV_IMAGE:$TAG" -f ./Dockerfile .
docker push "$DEV_IMAGE:$TAG"
docker tag "$DEV_IMAGE:$TAG" "$DEV_IMAGE:develop"
docker push "$DEV_IMAGE:develop"
exit 0
fi
if [ "$BRANCH" = "main" ]; then
sudo apt-get update -y
sudo apt-get install -y skopeo
if [ -z "${DEV_USER:-}" ] || [ -z "${DEV_PASS:-}" ]; then
echo "Missing Harbor DEV credentials (HARBOR_DEV_USERNAME/HARBOR_DEV_PASSWORD or HARBOR_USERNAME/HARBOR_PASSWORD)." >&2
exit 1
fi
if [ -z "${PROD_USER:-}" ] || [ -z "${PROD_PASS:-}" ]; then
echo "Missing Harbor PROD credentials (HARBOR_PROD_USERNAME/HARBOR_PROD_PASSWORD or HARBOR_USERNAME/HARBOR_PASSWORD)." >&2
exit 1
fi
# Merge commit: HEAD has 2 parents; HEAD^2 is the merged branch tip.
PARENTS="$(git rev-list --parents -n 1 HEAD)"
set -- $PARENTS
SOURCE_SHA="${3:-${1:-}}"
if [ -z "$SOURCE_SHA" ]; then
SOURCE_SHA="${{ gitea.sha }}"
fi
TAG="$(echo "$SOURCE_SHA" | cut -c1-7)"
# Promote the exact artifact built on develop into prod (no rebuild).
skopeo inspect --creds "$DEV_USER:$DEV_PASS" "docker://$DEV_IMAGE:$TAG" >/dev/null
# Validate destination repository exists and auth works.
# Using list-tags avoids assuming a specific tag exists.
skopeo list-tags --creds "$PROD_USER:$PROD_PASS" "docker://$PROD_IMAGE" >/dev/null
skopeo copy --all \
--src-creds "$DEV_USER:$DEV_PASS" \
--dest-creds "$PROD_USER:$PROD_PASS" \
"docker://$DEV_IMAGE:$TAG" \
"docker://$PROD_IMAGE:$TAG"
# Optional: keep legacy tags working during migration.
if [ "${PROMOTE_LEGACY:-false}" = "true" ]; then
skopeo copy --all \
--src-creds "$DEV_USER:$DEV_PASS" \
--dest-creds "$LEGACY_USER:$LEGACY_PASS" \
"docker://$DEV_IMAGE:$TAG" \
"docker://$LEGACY_IMAGE:$TAG"
skopeo copy --all \
--src-creds "$DEV_USER:$DEV_PASS" \
--dest-creds "$LEGACY_USER:$LEGACY_PASS" \
"docker://$DEV_IMAGE:$TAG" \
"docker://$LEGACY_IMAGE:latest"
fi
exit 0
fi
echo "Unsupported branch: $BRANCH" >&2
exit 1
git add "$MANIFEST_FILE"
git commit -m "chore: update image tag to $SHA_TAG [skip ci]"
git push origin main

View File

@@ -1,39 +1,55 @@
# Estágio 1: Build
FROM node:16-bullseye-slim AS builder
ARG NODE_VERSION=16.20
ARG DEBIAN_VARIANT=bullseye
FROM node:${NODE_VERSION}-${DEBIAN_VARIANT} AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install --legacy-peer-deps
COPY . .
RUN npm run build
FROM node:16-bullseye-slim
# Instalar dependências do Oracle
RUN apt-get update && apt-get install -y \
libaio1 \
unzip \
wget \
&& mkdir -p /opt/oracle
ARG INSTANTCLIENT_ZIP_URL=https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates wget unzip libaio1 libnsl2 \
&& rm -rf /var/lib/apt/lists/* \
&& mkdir -p /opt/oracle \
&& wget -q "${INSTANTCLIENT_ZIP_URL}" -O /opt/oracle/instantclient.zip \
&& unzip -q /opt/oracle/instantclient.zip -d /opt/oracle \
&& rm /opt/oracle/instantclient.zip \
&& rm -f /opt/oracle/instantclient_*/ojdbc*.jar \
/opt/oracle/instantclient_*/ucp*.jar \
/opt/oracle/instantclient_*/xstreams.jar \
/opt/oracle/instantclient_*/adrci \
/opt/oracle/instantclient_*/genezi \
/opt/oracle/instantclient_*/uidrvci \
&& ln -s "$(ls -d /opt/oracle/instantclient_* | head -n 1)" /opt/oracle/instantclient
# Instalar Oracle Instant Client
RUN wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-basic-linuxx64.zip -O /opt/oracle/client.zip && \
unzip /opt/oracle/client.zip -d /opt/oracle && \
rm /opt/oracle/client.zip && \
ln -s /opt/oracle/instantclient_* /opt/oracle/instantclient
# Configurar o sistema para encontrar as bibliotecas do Oracle
ENV LD_LIBRARY_PATH=/opt/oracle/instantclient
RUN echo "/opt/oracle/instantclient" > /etc/ld.so.conf.d/oracle-instantclient.conf && ldconfig
ENV PATH=/opt/oracle/instantclient:$PATH
COPY package*.json ./
ENV NPM_CONFIG_LEGACY_PEER_DEPS=true
RUN npm ci
COPY . .
RUN npm run build \
&& npm prune --omit=dev --legacy-peer-deps \
&& npm cache clean --force
FROM node:${NODE_VERSION}-${DEBIAN_VARIANT}-slim AS runtime
WORKDIR /app
# Copiar apenas o necessário do estágio anterior
COPY --from=builder /app/dist ./dist
ENV NODE_ENV=production
ENV LD_LIBRARY_PATH=/opt/oracle/instantclient
ENV PATH=/opt/oracle/instantclient:$PATH
RUN apt-get update \
&& apt-get install -y --no-install-recommends libaio1 libnsl2 \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /opt/oracle /opt/oracle
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
# Variáveis de ambiente padrão para o driver oracledb
ENV OCI_LIB_DIR=/opt/oracle/instantclient
ENV OCI_INC_DIR=/opt/oracle/instantclient/sdk/include
EXPOSE 8065
CMD ["npm", "run", "start:prod"]
CMD ["node", "dist/main"]

View File

@@ -1,76 +0,0 @@
# Documentação do Kubernetes
Este documento descreve a infraestrutura e configuração do Kubernetes para o projeto **Vendaweb-api**, utilizando uma abordagem GitOps com ArgoCD e Kustomize.
## Estrutura de Diretórios e Arquivos
A configuração do Kubernetes está localizada no diretório `k8s/` e segue uma estrutura organizada para facilitar a manutenção e escalabilidade:
```
k8s/
├── argocd/ # Configurações do ArgoCD
│ └── application-prod.yaml # Definição da Application para o ambiente de produção
├── base/ # Recursos base do Kubernetes (Kustomize Base)
│ ├── configmap.yaml # ConfigMap base
│ ├── deployment.yaml # Deployment base da aplicação
│ ├── kustomization.yaml # Arquivo principal do Kustomize Base
│ ├── secret.yaml # Secret base
│ └── service.yaml # Service base
└── overlays/ # Sobrescritas para diferentes ambientes (Kustomize Overlays)
└── prod/ # Ambiente de produção
├── application-prod.yaml
├── deployment-image-digest-patch.yaml
├── kustomization.yaml
└── service-patch.yaml
```
## Recursos Base (`k8s/base`)
O diretório `base` contém as definições padrão dos recursos que são comuns a todos os ambientes.
### Deployment (`deployment.yaml`)
- **Nome**: `vendaweb-api`
- **Replicas**: 15 (Configuração base)
- **Imagem**: `172.35.0.216/library/vendaweb-api:latest`
- **Porta do Container**: 8065
- **Resources**:
- Requests: CPU 100m, Memory 256Mi
- Limits: CPU 500m, Memory 512Mi
- **Probes**: Liveness, Readiness e Startup probes configurados no endpoint `/v1/health`.
- **Environment**: Configurações carregadas via ConfigMap e Secret.
### Service (`service.yaml`)
- **Tipo**: ClusterIP
- **Porta**: 8065 (TCP)
## Ambientes (`k8s/overlays`)
### Produção (`k8s/overlays/prod`)
A sobreposição de produção personaliza a configuração base para o ambiente produtivo.
- **Namespace**: `vendaweb-prod`
- **Patches**: Aplica modificações específicas (ex: digest da imagem, configurações específicas de serviço) via `kustomization.yaml`.
## Deploy com ArgoCD (`k8s/argocd`)
O deploy é gerenciado pelo ArgoCD, que sincroniza o estado do cluster com o repositório Git.
### Application (`application-prod.yaml`)
- **Nome**: `vendaweb-api-prod`
- **Namespace do ArgoCD**: `argocd`
- **Origem (Source)**:
- Repositório: `https://git.simplifiquehc.com.br/simplifique/Vendaweb-api.git`
- Revisão: `main`
- Path: `k8s/overlays/prod` (Aponta para o overlay de produção)
- **Destino (Destination)**:
- Cluster: `https://kubernetes.default.svc`
- Namespace: `vendaweb-api` (Nota: O patch define `vendaweb-prod`, verifique a consistência)
- **Sync Policy**: Automatizado com `selfHeal` ativado e criação automática de namespace.
---
**Observação**: Certifique-se de que as credenciais do Harbor (`imagePullSecrets`) estejam corretamente configuradas no namespace de destino para permitir o pull da imagem.

View File

@@ -14,7 +14,7 @@ Os workflows estão definidos no diretório `.gitea/workflows/`. O principal wor
Este workflow é acionado automaticamente no evento:
- `push`: Em qualquer branch (configuração atual `on: [push]`).
- `push`: Na branch `main`.
### Jobs
@@ -39,10 +39,13 @@ Este job é responsável por construir a imagem Docker e enviá-la para o regist
3. **Build e Push**
- Constrói a imagem Docker da aplicação.
- Tags geradas:
- `172.35.0.216/library/vendaweb-api:$TAG` (onde `$TAG` é o SHA do commit do Gitea `gitea.sha`)
- `172.35.0.216/library/vendaweb-api:latest`
- `git.simplifiquehc.com.br/simplifique/vendaweb-api:$TAG` (onde `$TAG` é o SHA curto do commit)
- `git.simplifiquehc.com.br/simplifique/vendaweb-api:latest`
- Envia ambas as tags para o registry.
4. **Atualizar Manifest e Push no Git**
- Atualiza `k8s/overlays/prod/deployment-image-digest-patch.yaml` para apontar para a tag `$TAG`.
## Variáveis e Segredos (Secrets)
Para que o workflow funcione corretamente, as seguintes secrets devem estar configuradas nas configurações do repositório no Gitea:

156
k8s/README.md Normal file
View File

@@ -0,0 +1,156 @@
# Kubernetes Infra (k8s) - vendaweb-api
Este diretorio contem os manifests Kubernetes do `vendaweb-api` usando Kustomize (base + overlays).
## Visao geral
- App: `vendaweb-api` (Deployment + Service)
- Porta HTTP do container/Service: `8067`
- Healthcheck usado pelos probes: `GET /v1/health`
- Config via `ConfigMap` + `Secret` (injetados com `envFrom`)
- Overlay prod:
- Namespace: `vendaweb-prod`
- Service: `NodePort` (porta externa `30001`)
- Replicas: `15`
## Estrutura
- `k8s/base/`
- `deployment.yaml`: deployment padrao (replicas 3), porta 8067, probes `/v1/health`, `imagePullSecrets: gitea-auth`
- `service.yaml`: `ClusterIP` expondo 8067
- `configmap.yaml`: variaveis nao sensiveis (ex.: Redis/DB host/port)
- `secret.yaml`: variaveis sensiveis (ex.: usuario/senha do DB)
- `kustomization.yaml`: agrega os recursos do base
- `k8s/overlays/prod/`
- `kustomization.yaml`: aplica patches e define `namespace: vendaweb-prod`
- `service-patch.yaml`: muda Service para `NodePort` e fixa `nodePort: 30001`
- `deployment-prod-patch.yaml`: ajusta `replicas: 15`
- `deployment-image-digest-patch.yaml`: sobrescreve a `image:` do container
- `k8s/argocd/application-prod.yaml`
- Aplica o overlay `k8s/overlays/prod` via Argo CD
- Sync automatizado com `selfHeal` e `prune`
## Portas e acesso
- Dentro do cluster: Service `vendaweb-api:8067`
- Overlay prod (NodePort): porta externa `30001` (mapeia para `8067`)
Notas:
- O processo Node/Nest escuta em `8067` (ver `src/main.ts`).
- A variavel `PORT` em `.env` nao e usada pelo bootstrap atual; o k8s esta configurado para 8067.
## Deploy com kubectl/kustomize
Gerar o YAML final (sem aplicar):
```bash
kubectl kustomize k8s/overlays/prod
```
Aplicar o overlay prod:
```bash
kubectl apply -k k8s/overlays/prod
```
Validar o que sera aplicado (dry-run):
```bash
kubectl apply -k k8s/overlays/prod --dry-run=server
```
Ver diffs (se seu kubectl suportar):
```bash
kubectl diff -k k8s/overlays/prod
```
## Argo CD (prod)
O Argo CD esta configurado em `k8s/argocd/application-prod.yaml` para:
- `path: k8s/overlays/prod`
- `targetRevision: main`
- `destination.namespace: vendaweb-prod` (com `CreateNamespace=true`)
Se voce esta usando Argo CD, o fluxo recomendado e:
- atualizar manifests no Git (overlay prod)
- deixar o Argo CD sincronizar automaticamente
## Configuracao (ConfigMap/Secret)
- `k8s/base/configmap.yaml` (`vendaweb-api-config`)
- `REDIS_HOST`, `REDIS_PORT`, `DB_HOST`, `DB_PORT`, `DB_SERVICE_NAME`
- `k8s/base/secret.yaml` (`vendaweb-api-secrets`)
- `DB_USERNAME`, `DB_PASSWORD`
Importante:
- O `Secret` esta em `stringData` no repositorio (texto puro). Para ambiente real, prefira um gerenciador de segredos (ExternalSecrets, SOPS, Vault etc.) e nao commite credenciais.
## Imagem e pipeline
O workflow `.gitea/workflows/deploy-api.yaml`:
- builda e publica `git.simplifiquehc.com.br/simplifique/vendaweb-api:<sha7>` e `:latest`
- atualiza `k8s/overlays/prod/deployment-image-digest-patch.yaml` para apontar para o tag do commit
Isso e pensado para o Argo CD detectar a alteracao no Git e aplicar.
## Comandos uteis (day-2)
Assumindo namespace `vendaweb-prod`:
```bash
kubectl -n vendaweb-prod get all
kubectl -n vendaweb-prod get pods -l app=vendaweb-api -o wide
kubectl -n vendaweb-prod describe deploy/vendaweb-api
kubectl -n vendaweb-prod describe pod -l app=vendaweb-api
```
Logs:
```bash
kubectl -n vendaweb-prod logs deploy/vendaweb-api --tail=200
kubectl -n vendaweb-prod logs -l app=vendaweb-api --tail=200 --all-containers
kubectl -n vendaweb-prod logs -l app=vendaweb-api -f
```
Rollout:
```bash
kubectl -n vendaweb-prod rollout status deploy/vendaweb-api
kubectl -n vendaweb-prod rollout history deploy/vendaweb-api
kubectl -n vendaweb-prod rollout restart deploy/vendaweb-api
```
Exec/Debug:
```bash
kubectl -n vendaweb-prod exec -it deploy/vendaweb-api -- sh
kubectl -n vendaweb-prod port-forward svc/vendaweb-api 8067:8067
```
## Troubleshooting rapido
- `ImagePullBackOff`:
- conferir `imagePullSecrets: gitea-auth` no namespace (`kubectl -n vendaweb-prod get secret gitea-auth`)
- conferir o valor de `image:` no overlay prod
- `CrashLoopBackOff`:
- ver logs do pod e eventos (`kubectl -n vendaweb-prod describe pod ...`)
- validar variaveis do `ConfigMap`/`Secret`
- Probes falhando:
- garantir que a rota `/v1/health` responde 200 e que a app esta ouvindo em `8067`
## Mudancas comuns
- Alterar porta externa (NodePort): `k8s/overlays/prod/service-patch.yaml`
- Alterar replicas em prod: `k8s/overlays/prod/deployment-prod-patch.yaml`
- Alterar imagem/tag em prod: `k8s/overlays/prod/deployment-image-digest-patch.yaml`
- Alterar envs: `k8s/base/configmap.yaml` e `k8s/base/secret.yaml`

View File

@@ -6,14 +6,22 @@ metadata:
spec:
project: default
source:
repoURL: https://git.simplifiquehc.com.br/simplifique/Vendaweb-api.git
repoURL: http://172.35.0.216:3000/simplifique/Vendaweb-api.git
targetRevision: main
path: k8s/overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: vendaweb-api
namespace: vendaweb-prod
syncPolicy:
automated:
selfHeal: true
prune: true
retry:
limit: 2
backoff:
duration: 5s
factor: 2
maxDuration: 3m
syncOptions:
- CreateNamespace=true
- PruneLast=true

View File

@@ -5,7 +5,15 @@ metadata:
labels:
app: vendaweb-api
spec:
replicas: 15
replicas: 3
revisionHistoryLimit: 5
minReadySeconds: 10
progressDeadlineSeconds: 600
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: vendaweb-api
@@ -15,10 +23,11 @@ spec:
app: vendaweb-api
spec:
imagePullSecrets:
- name: harbor-secret
- name: gitea-auth
terminationGracePeriodSeconds: 30
containers:
- name: api
image: 172.35.0.216/library/vendaweb-api:latest
image: 172.35.0.216:3000/simplifique/vendaweb-api:589fa29
imagePullPolicy: IfNotPresent
ports:
- name: http

View File

@@ -7,4 +7,4 @@ spec:
spec:
containers:
- name: api
image: 172.35.0.216/library/vendaweb-api@sha256:aac490fcb4ef7baa95f1df01fa50d2d44bdb4ed12b235e5dd89e1d7dc3cd0a3a
image: 172.35.0.216:3000/simplifique/vendaweb-api:3aa9673

View File

@@ -0,0 +1,6 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: vendaweb-api
spec:
replicas: 15

View File

@@ -7,5 +7,6 @@ resources:
- ../../base
patches:
- path: deployment-image-digest-patch.yaml
- path: service-patch.yaml
- path: deployment-prod-patch.yaml
- path: deployment-image-digest-patch.yaml

View File

@@ -14,7 +14,7 @@ export class AppController {
@Get('health')
@ApiOperation({ summary: 'Health check' })
healthCheck() {
return { status: 'SIMPLIFIQUE HOME CENTER 2026' };
return { status: 'NOVA VERSAO 2026' };
}
}

View File

@@ -129,19 +129,19 @@ export class ShippingService {
.createQueryBuilder('ESVRETIRALOJASCLIENTE')
.select([
'codfilial as "codigoFilial"'
,'numped as "numeroPedido"'
,'numnota as "numeroNota"'
,'dtfat as "dataFaturamento"'
,'datapedido as "dataPedido"'
,'codcli as "codigoCliente"'
,'cliente as "nomeCliente"'
,'codfilialretira as "codigoLoja"'
,'razaosocial as "nomeLoja"'
,'qtitens as "quantidadeItens"'
,'quantidade as "quantidade"'
, 'numped as "numeroPedido"'
, 'numnota as "numeroNota"'
, 'dtfat as "dataFaturamento"'
, 'datapedido as "dataPedido"'
, 'codcli as "codigoCliente"'
, 'cliente as "nomeCliente"'
, 'codfilialretira as "codigoLoja"'
, 'razaosocial as "nomeLoja"'
, 'qtitens as "quantidadeItens"'
, 'quantidade as "quantidade"'
])
.where("email = 'eduardoestevao.gyn@gmail.com'")
.andWhere("codfilial = :codfilial", {codfilial: id})
.andWhere("codfilial = :codfilial", { codfilial: id })
.getRawMany();
return deliveries;
@@ -169,13 +169,13 @@ export class ShippingService {
const sql = `SELECT PCDIASUTEIS.DATA as "dateDelivery",
NVL (PCDIASUTEIS.DIAROTA, 'N') as "delivery",
CASE WHEN NVL (PCDIASUTEIS.DIAROTA, 'N') = 'N' THEN 0
ELSE (PARAMFILIAL.OBTERCOMONUMBER ('CAPACIDADE_LOGISTICA', 12)) END as "deliverySize",
ELSE (PARAMFILIAL.OBTERCOMONUMBER ('CAPACIDADE_LOGISTICA', 1)) END as "deliverySize",
ROUND ( (NVL (VENDAS.TOTPESO, 0) / 1000), 3) as "saleWeigth",
CASE WHEN NVL (PCDIASUTEIS.DIAROTA, 'N') = 'N' THEN 0
ELSE ROUND (
GREATEST (
( ( PARAMFILIAL.OBTERCOMONUMBER ('CAPACIDADE_LOGISTICA',
12)
1)
* 1000)
- NVL (VENDAS.TOTPESO, 0))
/ 1000,
@@ -186,7 +186,9 @@ export class ShippingService {
FROM PCPEDC
WHERE PCPEDC.POSICAO IN ('L', 'M')
AND PCPEDC.CONDVENDA = 8
AND PCPEDC.CODFILIAL IN (12, 13, 4, 6)
AND EXISTS(SELECT 1 FROM PCPEDI
WHERE PCPEDI.NUMPED = PCPEDC.NUMPED
AND PCPEDI.CODFILIALRETIRA IN (1) )
AND EXISTS
(SELECT TV7.NUMPED
FROM PCPEDC TV7
@@ -194,15 +196,15 @@ export class ShippingService {
AND TV7.POSICAO = 'F')
AND PCPEDC.DTENTREGA >= TRUNC (SYSDATE) + 3
GROUP BY PCPEDC.DTENTREGA) VENDAS
WHERE PCDIASUTEIS.CODFILIAL = 12 AND PCDIASUTEIS.DATA BETWEEN TRUNC (SYSDATE) + 3 AND TRUNC(SYSDATE) + 20 --AND NVL(PCDIASUTEIS.DIAROTA,'N') = 'S'
WHERE PCDIASUTEIS.CODFILIAL = 1 AND PCDIASUTEIS.DATA BETWEEN TRUNC (SYSDATE) + 3 AND TRUNC(SYSDATE) + 20 --AND NVL(PCDIASUTEIS.DIAROTA,'N') = 'S'
AND PCDIASUTEIS.DATA = VENDAS.DTENTREGA(+)
ORDER BY PCDIASUTEIS.DATA `;
const data = await queryRunner.query(sql);
const sqlDeliveryDate = `SELECT TRUNC(SYSDATE) + esf_calcular_prazo_entrega_programada(TRUNC(SYSDATE),
'12',
129, '', 0, 500) as "date"
'1',
169, '', 0, 500) as "date"
FROM DUAL`;
const dataDeliveryDate = await queryRunner.query(sqlDeliveryDate);

View File

@@ -26,9 +26,6 @@ export class Pccidade {
@Column({ name: 'CODMUNSIAFI' })
codmunsiafi: number;
@Column({ name: 'DTMXSALTER' })
dtmxsalter: Date;
@Column({ name: 'LATITUDE' })
latitude: string;

View File

@@ -2,94 +2,91 @@ import { Column, Entity, PrimaryColumn } from "typeorm";
@Entity("PCORCAVENDAI")
export class Pcorcavendai {
@PrimaryColumn({name: 'NUMORCA'})
@PrimaryColumn({ name: 'NUMORCA' })
numorca: number;
@PrimaryColumn({name: 'CODPROD'})
@PrimaryColumn({ name: 'CODPROD' })
codprod: number;
@PrimaryColumn({name: 'NUMSEQ'})
@PrimaryColumn({ name: 'NUMSEQ' })
numseq: number;
@Column({name: 'DATA'})
@Column({ name: 'DATA' })
data: Date;
@Column({name: 'CODCLI'})
@Column({ name: 'CODCLI' })
codcli: number;
@Column({name: 'CODUSUR'})
@Column({ name: 'CODUSUR' })
codusur: number;
@Column({name: 'QT'})
@Column({ name: 'QT' })
qt: number;
@Column({name: 'PVENDA'})
@Column({ name: 'PVENDA' })
pvenda: number;
@Column({name: 'PTABELA'})
@Column({ name: 'PTABELA' })
ptabela: number;
@Column({name: 'NUMCAR'})
@Column({ name: 'NUMCAR' })
numcar: number;
@Column({name: 'POSICAO'})
@Column({ name: 'POSICAO' })
posicao: string;
@Column({name: 'ST'})
@Column({ name: 'ST' })
st: number;
@Column({name: 'VLCUSTOFIN'})
@Column({ name: 'VLCUSTOFIN' })
vlcustofin: number;
@Column({name: 'VLCUSTOREAL'})
@Column({ name: 'VLCUSTOREAL' })
vlcustoreal: number;
@Column({name: 'PERCOM'})
@Column({ name: 'PERCOM' })
percom: number;
@Column({name: 'PERDESC'})
@Column({ name: 'PERDESC' })
perdesc: number;
@Column({name: 'PVENDABASE'})
@Column({ name: 'PVENDABASE' })
pvendabase: number;
@Column({name: 'CODST'})
@Column({ name: 'CODST' })
codst: number;
@Column({name: 'CUSTOFINEST'})
@Column({ name: 'CUSTOFINEST' })
custofinest: number;
@Column({name: 'CODAUXILIAR'})
@Column({ name: 'CODAUXILIAR' })
codauxiliar: number;
@Column({name: 'CODFILIALRETIRA'})
@Column({ name: 'CODFILIALRETIRA' })
codfilialretira: string;
@Column({name: 'PORIGINAL'})
@Column({ name: 'PORIGINAL' })
poriginal: number;
@Column({name: 'VLCUSTOCONT'})
@Column({ name: 'VLCUSTOCONT' })
vlcustocont: number;
@Column({name: 'VLCUSTOREP'})
@Column({ name: 'VLCUSTOREP' })
vlcustorep: number;
@Column({name: 'PBASERCA'})
@Column({ name: 'PBASERCA' })
pbaserca: number;
@Column({name: 'PVENDA1'})
@Column({ name: 'PVENDA1' })
pvenda1: number;
@Column({name: 'TIPOENTREGA'})
@Column({ name: 'TIPOENTREGA' })
tipoentrega: string;
@Column({name: 'COMPLEMENTO'})
@Column({ name: 'COMPLEMENTO' })
complemento: string;
@Column({name: 'AMBIENTE'})
@Column({ name: 'AMBIENTE' })
ambiente: string;
@Column({name: 'RETIRAPOSTERIOR_IMEDIATA'})
rp_imediata: string;
}

View File

@@ -3,167 +3,165 @@ import { Column, Entity, PrimaryColumn } from "typeorm";
@Entity('PCPEDITEMP')
export class Pcpeditemp {
@Column({ name: 'TIPOINTEGRACAO' })
tipointegracao: string;
@Column({ name: 'TIPOINTEGRACAO' })
tipointegracao: string;
@Column({ name: 'OBSERVACAO_PC' })
observacao_pc: string;
@Column({ name: 'OBSERVACAO_PC' })
observacao_pc: string;
@Column({ name: 'NUMPEDCLI' })
numpedcli: string;
@Column({ name: 'NUMPEDCLI' })
numpedcli: string;
@PrimaryColumn({ name: 'NUMPEDRCA' })
numpedrca: number;
@PrimaryColumn({ name: 'NUMPEDRCA' })
numpedrca: number;
@Column({ name: 'CODCLI' })
codcli: number;
@Column({ name: 'CODCLI' })
codcli: number;
@Column({ name: 'CODUSUR' })
codusur: number;
@Column({ name: 'CODUSUR' })
codusur: number;
@Column({ name: 'DATA' })
data: Date;
@Column({ name: 'DATA' })
data: Date;
@PrimaryColumn({ name: 'CODPROD' })
codprod: number;
@PrimaryColumn({ name: 'CODPROD' })
codprod: number;
@Column({ name: 'QT' })
qt: number;
@Column({ name: 'QT' })
qt: number;
@Column({ name: 'QT_FATURADA' })
qt_faturada: number;
@Column({ name: 'QT_FATURADA' })
qt_faturada: number;
@Column({ name: 'PVENDA' })
pvenda: number;
@Column({ name: 'PVENDA' })
pvenda: number;
@Column({ name: 'PTABELA' })
ptabela: number;
@Column({ name: 'PTABELA' })
ptabela: number;
@Column({ name: 'PERDESC' })
perdesc: number;
@Column({ name: 'PERDESC' })
perdesc: number;
@PrimaryColumn({ name: 'NUMSEQ' })
numseq: number;
@PrimaryColumn({ name: 'NUMSEQ' })
numseq: number;
@Column({ name: 'CODAUXILIAR' })
codauxiliar: number;
@Column({ name: 'CODAUXILIAR' })
codauxiliar: number;
@Column({ name: 'CODCERTIFIC' })
codcertific: number;
@Column({ name: 'CODCERTIFIC' })
codcertific: number;
@Column({ name: 'CODFILIALRETIRA' })
codfilialretira: string;
@Column({ name: 'CODFILIALRETIRA' })
codfilialretira: string;
@Column({ name: 'NUMLOTE' })
numlote: string;
@Column({ name: 'NUMLOTE' })
numlote: string;
@Column({ name: 'COMPLEMENTO' })
complemento: string;
@Column({ name: 'COMPLEMENTO' })
complemento: string;
@Column({ name: 'CODPLPAG' })
codplpag: number;
@Column({ name: 'CODPLPAG' })
codplpag: number;
@Column({ name: 'CODPROMOCAO' })
codpromocao: string;
@Column({ name: 'CODPROMOCAO' })
codpromocao: string;
@Column({ name: 'PRAZOMEDIO' })
prazomedio: number;
@Column({ name: 'PRAZOMEDIO' })
prazomedio: number;
@Column({ name: 'LOCALIZACAO' })
localizacao: string;
@Column({ name: 'LOCALIZACAO' })
localizacao: string;
@Column({ name: 'PBONIFIC' })
pbonific: number;
@Column({ name: 'PBONIFIC' })
pbonific: number;
@Column({ name: 'CODDEGUSTACAO' })
coddegustacao: number;
@Column({ name: 'CODDEGUSTACAO' })
coddegustacao: number;
@Column({ name: 'PESOBRUTO' })
pesobruto: number;
@Column({ name: 'PESOBRUTO' })
pesobruto: number;
@Column({ name: 'EANCODPROD' })
eancodprod: number;
@Column({ name: 'EANCODPROD' })
eancodprod: number;
@Column({ name: 'CODNAOATENDIMENTO' })
codnaoatendimento: number;
@Column({ name: 'CODNAOATENDIMENTO' })
codnaoatendimento: number;
@Column({ name: 'OBSINTEGRACAO1' })
obsintegracao1: string;
@Column({ name: 'OBSINTEGRACAO1' })
obsintegracao1: string;
@Column({ name: 'OBSINTEGRACAO2' })
obsintegracao2: string;
@Column({ name: 'OBSINTEGRACAO2' })
obsintegracao2: string;
@Column({ name: 'NUMPEDWEB' })
numpedweb: number;
@Column({ name: 'NUMPEDWEB' })
numpedweb: number;
@Column({ name: 'TRANSACAO' })
transacao: number;
@Column({ name: 'TRANSACAO' })
transacao: number;
@Column({ name: 'IDVENDA' })
idvenda: number;
@Column({ name: 'IDVENDA' })
idvenda: number;
@Column({ name: 'INTEGRADORA' })
integradora: number;
@Column({ name: 'INTEGRADORA' })
integradora: number;
@Column({ name: 'CODRETORNO' })
codretorno: number;
@Column({ name: 'CODRETORNO' })
codretorno: number;
@Column({ name: 'COMISSAOATIM' })
comissaoatim: number;
@Column({ name: 'COMISSAOATIM' })
comissaoatim: number;
@Column({ name: 'TIPOENTREGA' })
tipoentrega: string;
@Column({ name: 'TIPOENTREGA' })
tipoentrega: string;
@Column({ name: 'CODRETORNOS' })
codretornos: string;
@Column({ name: 'CODRETORNOS' })
codretornos: string;
@Column({ name: 'DTINCLUSAO' })
dtinclusao: Date;
@Column({ name: 'DTINCLUSAO' })
dtinclusao: Date;
@Column({ name: 'CODPRODCESTA' })
codprodcesta: number;
@Column({ name: 'CODPRODCESTA' })
codprodcesta: number;
@Column({ name: 'BONIFIC' })
bonific: string;
@Column({ name: 'BONIFIC' })
bonific: string;
@Column({ name: 'DTIMP' })
dtimp: Date;
@Column({ name: 'DTIMP' })
dtimp: Date;
@Column({ name: 'PBASERCA' })
pbaserca: number;
@Column({ name: 'PBASERCA' })
pbaserca: number;
@Column({ name: 'VLFRETE' })
vlfrete: number;
@Column({ name: 'VLFRETE' })
vlfrete: number;
@Column({ name: 'FATORCONVERSAO' })
fatorconversao: number;
@Column({ name: 'FATORCONVERSAO' })
fatorconversao: number;
@Column({ name: 'IDKITPRODUTO' })
idkitproduto: string;
@Column({ name: 'IDKITPRODUTO' })
idkitproduto: string;
@Column({ name: 'MOVIMENTACONTACORRENTERCA' })
movimentacontacorrenterca: string;
@Column({ name: 'MOVIMENTACONTACORRENTERCA' })
movimentacontacorrenterca: string;
@Column({ name: 'PORIGINAL' })
poriginal: number;
@Column({ name: 'PORIGINAL' })
poriginal: number;
@Column({ name: 'ESC_EMBALAGEMPRESENTE' })
esc_embalagempresente: string;
@Column({ name: 'ESC_EMBALAGEMPRESENTE' })
esc_embalagempresente: string;
@Column({ name: 'QTUNITEMB' })
qtunitemb: number;
@Column({ name: 'QTUNITEMB' })
qtunitemb: number;
@Column({ name: 'IDREMESSAWEB' })
idremessaweb: number;
@Column({ name: 'IDREMESSAWEB' })
idremessaweb: number;
@Column({ name: 'CODFILIAL' })
codfilial: string;
@Column({ name: 'CODFILIAL' })
codfilial: string;
@Column({ name: 'CODCLIPARTILHA' })
codclipartilha: number;
@Column({ name: 'CODCLIPARTILHA' })
codclipartilha: number;
@Column({name: 'RETIRAPOSTERIOR_IMEDIATA'})
rp_imediata: string;
}

View File

@@ -6,20 +6,25 @@ import 'reflect-metadata';
import { CustomLoggerService } from './services/custom-logger.service';
async function bootstrap() {
const app = await NestFactory.create(AppModule, { cors: true, logger: new CustomLoggerService()});
const app = await NestFactory.create(AppModule, {
cors: true,
logger: new CustomLoggerService(),
});
app.enableCors();
app.use(compression());
const options = new DocumentBuilder()
.setTitle('API Venda web')
.setDescription(`API criada para realizar todo processo da venda assistida, como criação de oraçamento de venda, pedido de venda
.setDescription(
`API criada para realizar todo processo da venda assistida, como criação de oraçamento de venda, pedido de venda
cadastro de novos clientes, novos endereços. A API também fornece dados para o portal de parceiros como a manutenção
do cadastro de parceiros, consulta de venda de movimentação e pagamentos, e fechamento das comissões dos parceiros.`)
.setVersion("2023.1.2")
.addTag("VendaWeb")
.addTag("Auth")
do cadastro de parceiros, consulta de venda de movimentação e pagamentos, e fechamento das comissões dos parceiros.`,
)
.setVersion('2023.1.2')
.addTag('VendaWeb')
.addTag('Auth')
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup("docs", app, document);
await app.listen(8066);
SwaggerModule.setup('docs', app, document);
await app.listen(8067);
}
bootstrap();

View File

@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/camelcase */
import { HttpException, HttpStatus, Injectable,Inject } from '@nestjs/common';
import { HttpException, HttpStatus, Injectable, Inject } from '@nestjs/common';
import { ShoppingItens } from 'src/domain/entity/tables/estprevendai.entity';
import { Sale } from 'src/domain/entity/tables/estvenda.entity';
import { Pcpedctemp } from 'src/domain/entity/tables/pcpedctemp.entity';
@@ -527,6 +527,7 @@ export class OrderService {
preOrder.esc_ajustarfinanceiro = "N";
preOrder.esc_obternsu = "N";
preOrder.esc_vloutrasdespweb = 0;
preOrder.vloutrasdesp = cart.shippingValue;
preOrder.pedidopagoecommerce = "S";
preOrder.numpedmktplace = "";
preOrder.numitens = cart.itens.length;
@@ -538,7 +539,7 @@ export class OrderService {
//Dados do cliente
preOrder.codcli = cart.idCustomer;
preOrder.codpraca = (cart.shippingPriority == "M" && cart.idStorePlace != null ) ? cart.idStorePlace : customer.codpraca;
preOrder.codpraca = (cart.shippingPriority == "M" && cart.idStorePlace != null) ? cart.idStorePlace : customer.codpraca;
preOrder.fretedespacho = customer.fretedespacho;
preOrder.codfornecfrete = cart.carrierId;
@@ -585,8 +586,8 @@ export class OrderService {
itemOrder.codauxiliar = componente.ean;
itemOrder.codfilialretira = item.idStock;
itemOrder.tipoentrega = (item.deliveryMethod == 'RA') ? "RP" : item.deliveryMethod;
itemOrder.rp_imediata = (item.deliveryMethod == 'RA') ? "S" : "N";
if ( item.deliveryMethod == 'RA') {
// itemOrder.rp_imediata = (item.deliveryMethod == 'RA') ? "S" : "N";
if (item.deliveryMethod == 'RA') {
preOrder.dtentrega = new Date();
}
itemOrder.ptabela = Number.parseFloat(listPrice);
@@ -618,8 +619,8 @@ export class OrderService {
itemOrder.codauxiliar = item.ean;
itemOrder.codfilialretira = item.idStock;
itemOrder.tipoentrega = (item.deliveryMethod == 'RA') ? "RP" : item.deliveryMethod;
itemOrder.rp_imediata = (item.deliveryMethod == 'RA') ? "S" : "N";
if ( item.deliveryMethod == 'RA') {
//itemOrder.rp_imediata = (item.deliveryMethod == 'RA') ? "S" : "N";
if (item.deliveryMethod == 'RA') {
preOrder.dtentrega = new Date();
}
itemOrder.ptabela = item.listPrice;
@@ -643,34 +644,34 @@ export class OrderService {
//#endregion
if (cart.shippingValue > 0) {
const itemOrder = new Pcpeditemp();
itemOrder.tipointegracao = "W";
itemOrder.integradora = 10;
itemOrder.numpedrca = idPreOrder;
itemOrder.numpedweb = idPreOrder;
itemOrder.codcli = cart.idCustomer;
itemOrder.codusur = idSellerPreorder; //cart.idSeller;
itemOrder.numseq = numeroSeq;
itemOrder.codprod = 48500;
itemOrder.codauxiliar = 48500;
itemOrder.codfilialretira = '12';
itemOrder.tipoentrega = 'EF';
itemOrder.ptabela = Number.parseFloat(cart.shippingValue.toString());
itemOrder.pvenda = Number.parseFloat(cart.shippingValue.toString());
itemOrder.qt = 1;
itemOrder.data = new Date();
// if (cart.shippingValue > 0) {
// const itemOrder = new Pcpeditemp();
// itemOrder.tipointegracao = "W";
// itemOrder.integradora = 10;
// itemOrder.numpedrca = idPreOrder;
// itemOrder.numpedweb = idPreOrder;
// itemOrder.codcli = cart.idCustomer;
// itemOrder.codusur = idSellerPreorder; //cart.idSeller;
// itemOrder.numseq = numeroSeq;
// itemOrder.codprod = 48500;
// itemOrder.codauxiliar = 48500;
// itemOrder.codfilialretira = '12';
// itemOrder.tipoentrega = 'EF';
// itemOrder.ptabela = Number.parseFloat(cart.shippingValue.toString());
// itemOrder.pvenda = Number.parseFloat(cart.shippingValue.toString());
// itemOrder.qt = 1;
// itemOrder.data = new Date();
await queryRunner.manager
.createQueryBuilder()
.insert()
.into(Pcpeditemp)
.values(itemOrder)
.execute();
// await queryRunner.manager
// .createQueryBuilder()
// .insert()
// .into(Pcpeditemp)
// .values(itemOrder)
// .execute();
numeroSeq = numeroSeq + 1;
}
// numeroSeq = numeroSeq + 1;
// }
// execute some operations on this transaction:
await queryRunner.manager
@@ -1118,7 +1119,7 @@ export class OrderService {
sqlWhere += ` AND PCPEDC.NUMPED = ${idOrder} `;
}
if ( typeFilterProduct != '') {
if (typeFilterProduct != '') {
switch (typeFilterProduct) {
case 'ID':
sqlWhere += ` AND PCPEDI.CODPROD = ${productText} `;

View File

@@ -70,7 +70,7 @@ export class PreOrderService {
cart.id, cart.preCustomerName, cart.preCustomerPhone, cart.idSeller, idPreOrder]);
}
} else {
if ( cart.preCustomerDocument != null ) {
if (cart.preCustomerDocument != null) {
await queryRunner.query(`DELETE FROM ESTVENDAPRECLIENTE WHERE IDCART = :1 AND REGEXP_REPLACE(:CPF, '[^0-9]', '')`,
[cart.id, cart.preCustomerDocument]);
}
@@ -92,7 +92,7 @@ export class PreOrderService {
itemPreOrder.codcli = cart.idCustomer;
itemPreOrder.codprod = item.idProduct;
itemPreOrder.codauxiliar = item.ean;
itemPreOrder.codusur = ( idRca > 0 ) ? idRca : cart.idSeller;
itemPreOrder.codusur = (idRca > 0) ? idRca : cart.idSeller;
itemPreOrder.qt = item.quantity;
itemPreOrder.pvenda = item.salePrice;
itemPreOrder.ptabela = item.listPrice;
@@ -120,7 +120,7 @@ export class PreOrderService {
itemPreOrder.pvenda1 = 0;
itemPreOrder.tipoentrega = item.deliveryMethod;
// eslint-disable-next-line @typescript-eslint/camelcase
itemPreOrder.rp_imediata = (item.deliveryMethod == "RA") ? "S" : "N";
// itemPreOrder.rp_imediata = (item.deliveryMethod == "RA") ? "S" : "N";
itemPreOrder.complemento = item.descriptionAux;
itemPreOrder.ambiente = item.environment;
@@ -144,7 +144,7 @@ export class PreOrderService {
itemPreOrder.codcli = cart.idCustomer;
itemPreOrder.codprod = 48500;
itemPreOrder.codauxiliar = 48500;
itemPreOrder.codusur = ( idRca > 0 ) ? idRca : cart.idSeller;
itemPreOrder.codusur = (idRca > 0) ? idRca : cart.idSeller;
itemPreOrder.qt = 1;
itemPreOrder.pvenda = Number.parseFloat(cart.shippingValue.toString());
itemPreOrder.ptabela = Number.parseFloat(cart.shippingValue.toString());
@@ -201,7 +201,7 @@ export class PreOrderService {
preOrder.minuto = new Date().getMinutes();
preOrder.dtentrega = cart.shippingDate; // dateDelivery;
preOrder.codfilial = cart.saleStore,
preOrder.codusur = ( idRca > 0 ) ? idRca : cart.idSeller;
preOrder.codusur = (idRca > 0) ? idRca : cart.idSeller;
preOrder.codemitente = cart.userId;
preOrder.codusur3 = cart.idProfessional;
preOrder.tipoprioridadeentrega = cart.shippingPriority;
@@ -352,11 +352,11 @@ export class PreOrderService {
sql += ` AND PCORCAVENDAC.NUMORCA = ${idPreOrder} `;
}
if ( document.length > 0 ) {
if (document.length > 0) {
sql += ` AND REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '') = REGEXP_REPLACE(${document}, '[^0-9]', '') `;
}
if ( nameCustomer.length > 0 ) {
if (nameCustomer.length > 0) {
sql += ` AND PCCLIENT.CLIENTE LIKE UPPER('${nameCustomer}')||'%' `;
}

View File

@@ -125,7 +125,7 @@ export class SalesService {
.addSelect("\"esvlistaprodutos\".PRODUTO_COM_REDUCAO_PRECO", "downPrice")
.addSelect("\"esvlistaprodutos\".PRODUTO_EM_CAMPANHA", "compaing")
.addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base")
.addSelect("\"esvlistaprodutos\".LETRATINTOMETRICO", "letter")
.addSelect("\"esvlistaprodutos\".LETRABASETINTOMETRICO", "letter")
.addSelect("\"esvlistaprodutos\".LINHATINTOMETRICO", "line")
.addSelect("\"esvlistaprodutos\".LITRAGEM", "can")
.addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock")
@@ -184,7 +184,7 @@ export class SalesService {
.addSelect("\"esvlistaprodutos\".PRODUTO_COM_REDUCAO_PRECO", "downPrice")
.addSelect("\"esvlistaprodutos\".PRODUTO_EM_CAMPANHA", "compaing")
.addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base")
.addSelect("\"esvlistaprodutos\".LETRATINTOMETRICO", "letter")
.addSelect("\"esvlistaprodutos\".LETRABASETINTOMETRICO", "letter")
.addSelect("\"esvlistaprodutos\".LINHATINTOMETRICO", "line")
.addSelect("\"esvlistaprodutos\".LITRAGEM", "can")
.addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock")
@@ -262,7 +262,7 @@ export class SalesService {
.addSelect("\"esvlistaprodutos\".PRODUTO_COM_REDUCAO_PRECO", "downPrice")
.addSelect("\"esvlistaprodutos\".PRODUTO_EM_CAMPANHA", "compaing")
.addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base")
.addSelect("\"esvlistaprodutos\".LETRATINTOMETRICO", "letter")
.addSelect("\"esvlistaprodutos\".LETRABASETINTOMETRICO", "letter")
.addSelect("\"esvlistaprodutos\".LINHATINTOMETRICO", "line")
.addSelect("\"esvlistaprodutos\".LITRAGEM", "can")
.addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock")
@@ -328,7 +328,7 @@ export class SalesService {
.addSelect("\"esvlistaprodutos\".PRODUTO_COM_REDUCAO_PRECO", "downPrice")
.addSelect("\"esvlistaprodutos\".PRODUTO_EM_CAMPANHA", "compaing")
.addSelect("\"esvlistaprodutos\".BASETINTOMETRICO", "base")
.addSelect("\"esvlistaprodutos\".LETRATINTOMETRICO", "letter")
.addSelect("\"esvlistaprodutos\".LETRABASETINTOMETRICO", "letter")
.addSelect("\"esvlistaprodutos\".LINHATINTOMETRICO", "line")
.addSelect("\"esvlistaprodutos\".LITRAGEM", "can")
.addSelect("\"esvlistaprodutos\".QUANTIDADE_ESTOQUE_GERAL", "full_stock")
@@ -1613,7 +1613,7 @@ export class SalesService {
// const sql = `SELECT ESF_CALCULAR_PRAZO_ENTREGA(TO_DATE('${saleDate}', 'DD-MM-YYYY')) AS "days" FROM DUAL`;
const timeDays = await queryRunner.query(sql);
const sqlRetiraPosterior = `SELECT ( PROXIMO_DIA_UTIL(TO_DATE('${saleDate}', 'DD-MM-YYYY'), '4') - TRUNC(SYSDATE) ) AS "days" FROM DUAL`;
const sqlRetiraPosterior = `SELECT ( PROXIMO_DIA_UTIL(TO_DATE('${saleDate}', 'DD-MM-YYYY'), '1') - TRUNC(SYSDATE) ) AS "days" FROM DUAL`;
const timeDaysRetiraPosterior = await queryRunner.query(sqlRetiraPosterior);
return { deliveryDays: timeDays[0].days, retiraPosteriorDays: timeDaysRetiraPosterior[0].days };

View File

@@ -6,15 +6,16 @@ import { OrderDiscount } from 'src/domain/models/order-discount.model';
import { OrderTaxDelivery } from 'src/domain/models/order-taxdelivery.model';
import { LogOrder } from 'src/domain/models/log-order.model';
import { ApiTags } from '@nestjs/swagger';
import { Cart } from 'src/domain/models/cart.model';
@ApiTags('Shopping')
@Controller('api/v1/shopping')
export class ShoppingController {
constructor(private shoppingService: ShoppingService){}
constructor(private shoppingService: ShoppingService) { }
@Get('cart/:id')
async getCart(@Param('id') id: string){
async getCart(@Param('id') id: string) {
try {
const cart = await this.shoppingService.GetItensCart(id);
if (cart == null || cart.length == 0)
@@ -27,10 +28,10 @@ export class ShoppingController {
}
@Get(':id')
async getPreVenda(@Param('id') id: string ){
async getPreVenda(@Param('id') id: string) {
try {
const cart = await this.shoppingService.getShopping(id);
if (cart == null )
if (cart == null)
throw new HttpException("Carrinho de compras não encontrado", HttpStatus.NOT_FOUND);
return cart;
} catch (error) {
@@ -39,15 +40,24 @@ export class ShoppingController {
}
}
@Put('cart')
async updateCart(@Body() cart: Cart) {
try {
return await this.shoppingService.updateShopping(cart);
} catch (error) {
throw new HttpException(error.message, HttpStatus.BAD_REQUEST);
}
}
@Get('cart/:idcart/item/:idProduct/tipoentrega/:deliveryType')
async getItemCart(@Req() request, @Param('idCart') idCart: string,
@Param('idProduct') idProduct: string, @Param('deliveryType') deliveryType: string){
@Param('idProduct') idProduct: string, @Param('deliveryType') deliveryType: string) {
let store = '99';
try {
if (request.headers['x-store'])
store = request.headers['x-store'];
const cart = await this.shoppingService.getItemCart(idCart, idProduct, store, deliveryType);
if (cart == null )
if (cart == null)
throw new HttpException("Item não foi encontrado no carrinho de compras.", HttpStatus.NOT_FOUND);
return cart;
} catch (error) {
@@ -57,8 +67,8 @@ export class ShoppingController {
}
@Get('cart/lot/:productId/:customerId')
async getLotProduct( @Req() request, @Param('productId') productId: number,
@Param('customerId') customerId: number ) {
async getLotProduct(@Req() request, @Param('productId') productId: number,
@Param('customerId') customerId: number) {
let store = '99';
try {
if (request.headers['x-store'])
@@ -73,7 +83,7 @@ export class ShoppingController {
@Post('item')
async createItemShopping(@Body() item: ShoppingItem){
async createItemShopping(@Body() item: ShoppingItem) {
console.log('createItemShopping')
try {
return await this.shoppingService.createItemCart(item);
@@ -83,7 +93,7 @@ export class ShoppingController {
}
@Post('log')
async logOrderShopping(@Body() logOrder: LogOrder){
async logOrderShopping(@Body() logOrder: LogOrder) {
try {
console.log('logOrderShopping')
return await this.shoppingService.createLogShopping(logOrder);
@@ -93,10 +103,10 @@ export class ShoppingController {
}
@Put('item')
async updateQuantityItem(@Body() item: ShoppingItem){
async updateQuantityItem(@Body() item: ShoppingItem) {
console.log(item);
try {
if (item.id == null){
if (item.id == null) {
throw new HttpException('Item sem Id informado, faça a inclusão do item no carrinho.', HttpStatus.BAD_REQUEST);
}
const itemCreate = await this.shoppingService.updateItem(item);
@@ -107,10 +117,10 @@ export class ShoppingController {
}
@Put('item/discount')
async updatePriceItem(@Body() item: ShoppingItem){
async updatePriceItem(@Body() item: ShoppingItem) {
console.log(item);
try {
if (item.id == null){
if (item.id == null) {
throw new HttpException('Item sem Id informado, faça a inclusão do item no carrinho.', HttpStatus.BAD_REQUEST);
}
const itemCreate = await this.shoppingService.updatePrice(item);
@@ -142,7 +152,7 @@ export class ShoppingController {
}
@Delete('item/delete/:id')
async deleteItem(@Param('id') id: string){
async deleteItem(@Param('id') id: string) {
try {
await this.shoppingService.deleteItem(id);
return new ResultModel(true, 'Item excluído com sucesso!', id, null,);
@@ -165,4 +175,4 @@ export class ShoppingController {
}
}
}

View File

@@ -8,6 +8,7 @@ import { Shopping } from 'src/domain/entity/tables/estprevendac.entity';
import { OrderTaxDelivery } from 'src/domain/models/order-taxdelivery.model';
import { connectionOptions } from 'src/configs/typeorm.config';
import { LogOrder } from 'src/domain/models/log-order.model';
import { Cart } from 'src/domain/models/cart.model';
@Injectable()
export class ShoppingService {
@@ -167,7 +168,7 @@ export class ShoppingService {
AND E.CODFILIAL = '${itemShopping.stockStore}'`);
let quantityStock = 0;
if ( dataStockItem.length > 0 ) {
if (dataStockItem.length > 0) {
quantityStock = dataStockItem[0].quantityStock;
}
@@ -605,6 +606,39 @@ export class ShoppingService {
}
}
async updateShopping(shopping: any) {
const connection = new Connection(connectionOptions);
await connection.connect();
const queryRunner = connection.createQueryRunner();
await queryRunner.connect();
try {
console.log(JSON.stringify(shopping));
const sql = `UPDATE ESTPREVENDAC
SET ESTPREVENDAC.CODCLI = :codcli
,ESTPREVENDAC.codendentcli = :codendentcli
,ESTPREVENDAC.codplpag = :codplpag
,ESTPREVENDAC.codcob = :codcob
,ESTPREVENDAC.codfilial = :codfilial
WHERE ID = :id `;
await queryRunner.query(sql, [
shopping.codcli,
shopping.codendentcli,
shopping.codplpag,
shopping.codcob,
shopping.saleStore,
shopping.id
]);
return shopping;
} catch (error) {
throw error;
} finally {
await queryRunner.release();
await connection.close();
}
}
async updatePriceShopping(idCart: string, idPaymentPlan: number) {
const connection = new Connection(connectionOptions);
await connection.connect();