fix: (codigo-acesso) ajustado filtros
This commit is contained in:
parent
8e95828f85
commit
67a82f2189
7 changed files with 169 additions and 47 deletions
|
|
@ -54,6 +54,14 @@ func (h *Handler) List(c *gin.Context) {
|
|||
|
||||
resp := make([]map[string]interface{}, len(codes))
|
||||
for i, v := range codes {
|
||||
var empID, empNome string
|
||||
if v.EmpresaID.Valid {
|
||||
empID = uuid.UUID(v.EmpresaID.Bytes).String()
|
||||
}
|
||||
if v.EmpresaNome.Valid {
|
||||
empNome = v.EmpresaNome.String
|
||||
}
|
||||
|
||||
resp[i] = map[string]interface{}{
|
||||
"id": uuid.UUID(v.ID.Bytes).String(),
|
||||
"codigo": v.Codigo,
|
||||
|
|
@ -63,6 +71,8 @@ func (h *Handler) List(c *gin.Context) {
|
|||
"expira_em": v.ExpiraEm.Time,
|
||||
"ativo": v.Ativo,
|
||||
"usos": v.Usos,
|
||||
"empresa_id": empID,
|
||||
"empresa_nome": empNome,
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
|
|
@ -103,7 +113,7 @@ func (h *Handler) Verify(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
err := h.service.Verify(c.Request.Context(), code)
|
||||
codeData, err := h.service.Verify(c.Request.Context(), code)
|
||||
if err != nil {
|
||||
// Distinguish validation error from DB error strictly?
|
||||
// For security, just say invalid.
|
||||
|
|
@ -117,5 +127,14 @@ func (h *Handler) Verify(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"valid": true})
|
||||
// Prepare response
|
||||
resp := gin.H{"valid": true}
|
||||
if codeData.EmpresaID.Valid {
|
||||
resp["empresa_id"] = uuid.UUID(codeData.EmpresaID.Bytes).String()
|
||||
}
|
||||
if codeData.EmpresaNome.Valid {
|
||||
resp["empresa_nome"] = codeData.EmpresaNome.String
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ type CreateCodigoInput struct {
|
|||
Codigo string `json:"codigo"`
|
||||
Descricao string `json:"descricao"`
|
||||
ValidadeDias int32 `json:"validade_dias"`
|
||||
EmpresaID string `json:"empresa_id"`
|
||||
}
|
||||
|
||||
func (s *Service) Create(ctx context.Context, input CreateCodigoInput) (generated.CodigosAcesso, error) {
|
||||
|
|
@ -40,16 +41,26 @@ func (s *Service) Create(ctx context.Context, input CreateCodigoInput) (generate
|
|||
expiraEm = time.Now().Add(time.Duration(days) * 24 * time.Hour)
|
||||
}
|
||||
|
||||
var empresaUUID pgtype.UUID
|
||||
if input.EmpresaID != "" {
|
||||
parsed, err := uuid.Parse(input.EmpresaID)
|
||||
if err == nil {
|
||||
empresaUUID.Bytes = parsed
|
||||
empresaUUID.Valid = true
|
||||
}
|
||||
}
|
||||
|
||||
return s.q.CreateCodigoAcesso(ctx, generated.CreateCodigoAcessoParams{
|
||||
Codigo: input.Codigo,
|
||||
Descricao: pgtype.Text{String: input.Descricao, Valid: input.Descricao != ""},
|
||||
ValidadeDias: days,
|
||||
ExpiraEm: pgtype.Timestamptz{Time: expiraEm, Valid: true},
|
||||
Ativo: true,
|
||||
EmpresaID: empresaUUID,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Service) List(ctx context.Context) ([]generated.CodigosAcesso, error) {
|
||||
func (s *Service) List(ctx context.Context) ([]generated.ListCodigosAcessoRow, error) {
|
||||
return s.q.ListCodigosAcesso(ctx)
|
||||
}
|
||||
|
||||
|
|
@ -67,7 +78,7 @@ func (s *Service) Delete(ctx context.Context, id string) error {
|
|||
return s.q.DeleteCodigoAcesso(ctx, pgUUID)
|
||||
}
|
||||
|
||||
func (s *Service) GetByCode(ctx context.Context, code string) (generated.CodigosAcesso, error) {
|
||||
func (s *Service) GetByCode(ctx context.Context, code string) (generated.GetCodigoAcessoRow, error) {
|
||||
return s.q.GetCodigoAcesso(ctx, code)
|
||||
}
|
||||
|
||||
|
|
@ -87,19 +98,19 @@ func (e *AppError) Error() string {
|
|||
return e.Message
|
||||
}
|
||||
|
||||
func (s *Service) Verify(ctx context.Context, code string) error {
|
||||
func (s *Service) Verify(ctx context.Context, code string) (*generated.GetCodigoAcessoRow, error) {
|
||||
c, err := s.q.GetCodigoAcesso(ctx, code)
|
||||
if err != nil {
|
||||
return err // Not found or DB error
|
||||
return nil, err // Not found or DB error
|
||||
}
|
||||
|
||||
if !c.Ativo {
|
||||
return &AppError{Message: "Código inativo"}
|
||||
return nil, &AppError{Message: "Código inativo"}
|
||||
}
|
||||
|
||||
if time.Now().After(c.ExpiraEm.Time) {
|
||||
return &AppError{Message: "Código expirado"}
|
||||
return nil, &AppError{Message: "Código expirado"}
|
||||
}
|
||||
|
||||
return nil
|
||||
return &c, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@ import (
|
|||
|
||||
const createCodigoAcesso = `-- name: CreateCodigoAcesso :one
|
||||
INSERT INTO codigos_acesso (
|
||||
codigo, descricao, validade_dias, expira_em, ativo
|
||||
codigo, descricao, validade_dias, expira_em, ativo, empresa_id
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5
|
||||
$1, $2, $3, $4, $5, $6
|
||||
)
|
||||
RETURNING id, codigo, descricao, validade_dias, criado_em, expira_em, ativo, usos
|
||||
RETURNING id, codigo, descricao, validade_dias, criado_em, expira_em, ativo, usos, empresa_id
|
||||
`
|
||||
|
||||
type CreateCodigoAcessoParams struct {
|
||||
|
|
@ -26,6 +26,7 @@ type CreateCodigoAcessoParams struct {
|
|||
ValidadeDias int32 `json:"validade_dias"`
|
||||
ExpiraEm pgtype.Timestamptz `json:"expira_em"`
|
||||
Ativo bool `json:"ativo"`
|
||||
EmpresaID pgtype.UUID `json:"empresa_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateCodigoAcesso(ctx context.Context, arg CreateCodigoAcessoParams) (CodigosAcesso, error) {
|
||||
|
|
@ -35,6 +36,7 @@ func (q *Queries) CreateCodigoAcesso(ctx context.Context, arg CreateCodigoAcesso
|
|||
arg.ValidadeDias,
|
||||
arg.ExpiraEm,
|
||||
arg.Ativo,
|
||||
arg.EmpresaID,
|
||||
)
|
||||
var i CodigosAcesso
|
||||
err := row.Scan(
|
||||
|
|
@ -46,6 +48,7 @@ func (q *Queries) CreateCodigoAcesso(ctx context.Context, arg CreateCodigoAcesso
|
|||
&i.ExpiraEm,
|
||||
&i.Ativo,
|
||||
&i.Usos,
|
||||
&i.EmpresaID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
|
@ -61,13 +64,28 @@ func (q *Queries) DeleteCodigoAcesso(ctx context.Context, id pgtype.UUID) error
|
|||
}
|
||||
|
||||
const getCodigoAcesso = `-- name: GetCodigoAcesso :one
|
||||
SELECT id, codigo, descricao, validade_dias, criado_em, expira_em, ativo, usos FROM codigos_acesso
|
||||
WHERE codigo = $1 LIMIT 1
|
||||
SELECT c.id, c.codigo, c.descricao, c.validade_dias, c.criado_em, c.expira_em, c.ativo, c.usos, c.empresa_id, e.nome as empresa_nome
|
||||
FROM codigos_acesso c
|
||||
LEFT JOIN empresas e ON c.empresa_id = e.id
|
||||
WHERE c.codigo = $1 LIMIT 1
|
||||
`
|
||||
|
||||
func (q *Queries) GetCodigoAcesso(ctx context.Context, codigo string) (CodigosAcesso, error) {
|
||||
type GetCodigoAcessoRow struct {
|
||||
ID pgtype.UUID `json:"id"`
|
||||
Codigo string `json:"codigo"`
|
||||
Descricao pgtype.Text `json:"descricao"`
|
||||
ValidadeDias int32 `json:"validade_dias"`
|
||||
CriadoEm pgtype.Timestamptz `json:"criado_em"`
|
||||
ExpiraEm pgtype.Timestamptz `json:"expira_em"`
|
||||
Ativo bool `json:"ativo"`
|
||||
Usos int32 `json:"usos"`
|
||||
EmpresaID pgtype.UUID `json:"empresa_id"`
|
||||
EmpresaNome pgtype.Text `json:"empresa_nome"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetCodigoAcesso(ctx context.Context, codigo string) (GetCodigoAcessoRow, error) {
|
||||
row := q.db.QueryRow(ctx, getCodigoAcesso, codigo)
|
||||
var i CodigosAcesso
|
||||
var i GetCodigoAcessoRow
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Codigo,
|
||||
|
|
@ -77,6 +95,8 @@ func (q *Queries) GetCodigoAcesso(ctx context.Context, codigo string) (CodigosAc
|
|||
&i.ExpiraEm,
|
||||
&i.Ativo,
|
||||
&i.Usos,
|
||||
&i.EmpresaID,
|
||||
&i.EmpresaNome,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
|
@ -93,19 +113,34 @@ func (q *Queries) IncrementCodigoAcessoUso(ctx context.Context, id pgtype.UUID)
|
|||
}
|
||||
|
||||
const listCodigosAcesso = `-- name: ListCodigosAcesso :many
|
||||
SELECT id, codigo, descricao, validade_dias, criado_em, expira_em, ativo, usos FROM codigos_acesso
|
||||
ORDER BY criado_em DESC
|
||||
SELECT c.id, c.codigo, c.descricao, c.validade_dias, c.criado_em, c.expira_em, c.ativo, c.usos, c.empresa_id, e.nome as empresa_nome
|
||||
FROM codigos_acesso c
|
||||
LEFT JOIN empresas e ON c.empresa_id = e.id
|
||||
ORDER BY c.criado_em DESC
|
||||
`
|
||||
|
||||
func (q *Queries) ListCodigosAcesso(ctx context.Context) ([]CodigosAcesso, error) {
|
||||
type ListCodigosAcessoRow struct {
|
||||
ID pgtype.UUID `json:"id"`
|
||||
Codigo string `json:"codigo"`
|
||||
Descricao pgtype.Text `json:"descricao"`
|
||||
ValidadeDias int32 `json:"validade_dias"`
|
||||
CriadoEm pgtype.Timestamptz `json:"criado_em"`
|
||||
ExpiraEm pgtype.Timestamptz `json:"expira_em"`
|
||||
Ativo bool `json:"ativo"`
|
||||
Usos int32 `json:"usos"`
|
||||
EmpresaID pgtype.UUID `json:"empresa_id"`
|
||||
EmpresaNome pgtype.Text `json:"empresa_nome"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListCodigosAcesso(ctx context.Context) ([]ListCodigosAcessoRow, error) {
|
||||
rows, err := q.db.Query(ctx, listCodigosAcesso)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []CodigosAcesso
|
||||
var items []ListCodigosAcessoRow
|
||||
for rows.Next() {
|
||||
var i CodigosAcesso
|
||||
var i ListCodigosAcessoRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.Codigo,
|
||||
|
|
@ -115,6 +150,8 @@ func (q *Queries) ListCodigosAcesso(ctx context.Context) ([]CodigosAcesso, error
|
|||
&i.ExpiraEm,
|
||||
&i.Ativo,
|
||||
&i.Usos,
|
||||
&i.EmpresaID,
|
||||
&i.EmpresaNome,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ type CodigosAcesso struct {
|
|||
ExpiraEm pgtype.Timestamptz `json:"expira_em"`
|
||||
Ativo bool `json:"ativo"`
|
||||
Usos int32 `json:"usos"`
|
||||
EmpresaID pgtype.UUID `json:"empresa_id"`
|
||||
}
|
||||
|
||||
type Curso struct {
|
||||
|
|
|
|||
|
|
@ -1,22 +1,26 @@
|
|||
-- name: CreateCodigoAcesso :one
|
||||
INSERT INTO codigos_acesso (
|
||||
codigo, descricao, validade_dias, expira_em, ativo
|
||||
codigo, descricao, validade_dias, expira_em, ativo, empresa_id
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5
|
||||
$1, $2, $3, $4, $5, $6
|
||||
)
|
||||
RETURNING *;
|
||||
|
||||
-- name: ListCodigosAcesso :many
|
||||
SELECT * FROM codigos_acesso
|
||||
ORDER BY criado_em DESC;
|
||||
SELECT c.*, e.nome as empresa_nome
|
||||
FROM codigos_acesso c
|
||||
LEFT JOIN empresas e ON c.empresa_id = e.id
|
||||
ORDER BY c.criado_em DESC;
|
||||
|
||||
-- name: DeleteCodigoAcesso :exec
|
||||
DELETE FROM codigos_acesso
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: GetCodigoAcesso :one
|
||||
SELECT * FROM codigos_acesso
|
||||
WHERE codigo = $1 LIMIT 1;
|
||||
SELECT c.*, e.nome as empresa_nome
|
||||
FROM codigos_acesso c
|
||||
LEFT JOIN empresas e ON c.empresa_id = e.id
|
||||
WHERE c.codigo = $1 LIMIT 1;
|
||||
|
||||
-- name: IncrementCodigoAcessoUso :exec
|
||||
UPDATE codigos_acesso
|
||||
|
|
|
|||
|
|
@ -440,7 +440,8 @@ CREATE TABLE IF NOT EXISTS codigos_acesso (
|
|||
criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
expira_em TIMESTAMPTZ NOT NULL,
|
||||
ativo BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
usos INT NOT NULL DEFAULT 0
|
||||
usos INT NOT NULL DEFAULT 0,
|
||||
empresa_id UUID REFERENCES empresas(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
-- Financeiro Extrato
|
||||
|
|
|
|||
|
|
@ -376,26 +376,75 @@ export const ImportData: React.FC = () => {
|
|||
|
||||
|
||||
if (activeTab === 'fot') {
|
||||
const fot = getStr(0);
|
||||
if (!fot) continue;
|
||||
// Parse Gastos
|
||||
let gastosStr = getStr(8);
|
||||
gastosStr = gastosStr.replace(/[R$\s.]/g, '').replace(',', '.');
|
||||
const gastos = parseFloat(gastosStr) || 0;
|
||||
// Dynamic Mapping for FOT
|
||||
let headerIdx = -1;
|
||||
const colMap: {[key: string]: number} = {};
|
||||
|
||||
// 1. Find header row
|
||||
for (let i = 0; i < 20 && i < rows.length; i++) {
|
||||
const rowStrings = (rows[i] as any[]).map(c => String(c).toLowerCase().trim());
|
||||
if (rowStrings.some(s => s === 'fot' || s === 'empresa' || s.includes('contrato'))) {
|
||||
headerIdx = i;
|
||||
rowStrings.forEach((h, idx) => {
|
||||
if (h === 'fot' || h.includes('contrato')) colMap['fot'] = idx;
|
||||
else if (h === 'empresa' || h.includes('cliente')) colMap['empresa'] = idx;
|
||||
else if (h.includes('curso')) colMap['curso'] = idx;
|
||||
else if (h.includes('obs') || h.includes('observa')) colMap['obs'] = idx;
|
||||
else if (h.includes('institui')) colMap['instituicao'] = idx;
|
||||
else if (h.includes('ano') || h.includes('formatur')) colMap['ano'] = idx;
|
||||
else if (h === 'cidade') colMap['cidade'] = idx;
|
||||
else if (h === 'estado' || h === 'uf') colMap['estado'] = idx;
|
||||
else if (h.includes('gasto') || h.includes('capta')) colMap['gastos'] = idx;
|
||||
else if (h.includes('pré') || h.includes('pre') || h.includes('venda')) colMap['prevenda'] = idx;
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const item: ImportFotInput = {
|
||||
fot: fot,
|
||||
empresa_nome: getStr(1),
|
||||
curso_nome: getStr(2),
|
||||
observacoes: getStr(3),
|
||||
instituicao: getStr(4),
|
||||
ano_formatura_label: getStr(5),
|
||||
cidade: getStr(6),
|
||||
estado: getStr(7),
|
||||
gastos_captacao: gastos,
|
||||
pre_venda: getStr(9).toLowerCase().includes('sim'),
|
||||
};
|
||||
mappedData.push(item);
|
||||
if (headerIdx === -1) {
|
||||
// Fallback to indices if not found (Legacy/Default)
|
||||
headerIdx = 0;
|
||||
// Default: FOT, Empresa, Curso, Obs, Inst, Ano, Cid, UF, Gastos, Prevenda
|
||||
colMap['fot'] = 0; colMap['empresa'] = 1; colMap['curso'] = 2; colMap['obs'] = 3;
|
||||
colMap['instituicao'] = 4; colMap['ano'] = 5; colMap['cidade'] = 6; colMap['estado'] = 7;
|
||||
colMap['gastos'] = 8; colMap['prevenda'] = 9;
|
||||
}
|
||||
|
||||
// Iterate
|
||||
for (let i = headerIdx + 1; i < rows.length; i++) {
|
||||
const row = rows[i] as any[];
|
||||
if (!row || row.length === 0) continue;
|
||||
|
||||
const getCol = (key: string) => {
|
||||
const idx = colMap[key];
|
||||
if (idx === undefined || idx < 0) return "";
|
||||
return row[idx] !== undefined ? String(row[idx]).trim() : "";
|
||||
};
|
||||
|
||||
const fot = getCol('fot');
|
||||
|
||||
// Strict validation: Must have at least 3 chars to be valid FOT (usually 5 digits)
|
||||
if (!fot || fot.length < 3) continue;
|
||||
|
||||
// Parse Gastos
|
||||
let gastosStr = getCol('gastos');
|
||||
gastosStr = gastosStr.replace(/[R$\s.]/g, '').replace(',', '.');
|
||||
const gastos = parseFloat(gastosStr) || 0;
|
||||
|
||||
const item: ImportFotInput = {
|
||||
fot: fot,
|
||||
empresa_nome: getCol('empresa'),
|
||||
curso_nome: getCol('curso'),
|
||||
observacoes: getCol('obs'),
|
||||
instituicao: getCol('instituicao'),
|
||||
ano_formatura_label: getCol('ano'),
|
||||
cidade: getCol('cidade'),
|
||||
estado: getCol('estado'),
|
||||
gastos_captacao: gastos,
|
||||
pre_venda: getCol('prevenda').toLowerCase().includes('sim'),
|
||||
};
|
||||
mappedData.push(item);
|
||||
}
|
||||
|
||||
} else if (activeTab === 'agenda') {
|
||||
const fot = getStr(0);
|
||||
|
|
|
|||
Loading…
Reference in a new issue