feat: added api usage period by date
							parent
							
								
									feb05b3e6e
								
							
						
					
					
						commit
						fab7e2b72a
					
				| 
						 | 
					@ -1,10 +1,12 @@
 | 
				
			||||||
const { StatusCodes } = require("http-status-codes")
 | 
					const { StatusCodes } = require("http-status-codes")
 | 
				
			||||||
const API_Pricing = require("../models/API_Pricing.js")
 | 
					const API_Pricing = require("../models/API_Pricing.js")
 | 
				
			||||||
 | 
					const mongoose = require('mongoose');
 | 
				
			||||||
const {
 | 
					const {
 | 
				
			||||||
    mustContainProperties,
 | 
					    mustContainProperties,
 | 
				
			||||||
    calculateApiUsage,
 | 
					    calculateApiUsage,
 | 
				
			||||||
} = require('../utils')
 | 
					} = require('../utils')
 | 
				
			||||||
const API_Usage = require("../models/API_Usage.js")
 | 
					const API_Usage = require("../models/API_Usage.js")
 | 
				
			||||||
 | 
					const API_Products = require("../models/API_Products.js")
 | 
				
			||||||
const billingSumUsage = require("../utils/billingSumUsage.js")
 | 
					const billingSumUsage = require("../utils/billingSumUsage.js")
 | 
				
			||||||
const moment = require('moment')
 | 
					const moment = require('moment')
 | 
				
			||||||
const API_Call = require("../models/API_Call.js")
 | 
					const API_Call = require("../models/API_Call.js")
 | 
				
			||||||
| 
						 | 
					@ -47,6 +49,145 @@ const setApiPricing = async (req, res) => {
 | 
				
			||||||
    res.status(StatusCodes.OK).json({ apiPricing })
 | 
					    res.status(StatusCodes.OK).json({ apiPricing })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const updateProductPricing = async (req, res) => {
 | 
				
			||||||
 | 
					    const { price, name, description } = req.body;
 | 
				
			||||||
 | 
					    const { id } = req.params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!mongoose.Types.ObjectId.isValid(id)) {
 | 
				
			||||||
 | 
					        return res.status(StatusCodes.BAD_REQUEST).json({
 | 
				
			||||||
 | 
					            error: 'ID do produto inválido.'
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let existingProduct = await API_Products.findById(id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!existingProduct) {
 | 
				
			||||||
 | 
					        return res.status(StatusCodes.NOT_FOUND).json({
 | 
				
			||||||
 | 
					            error: 'Produto não encontrado.'
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (price) {
 | 
				
			||||||
 | 
					        const activePriceIndex = existingProduct.priceHistory.findIndex(priceEntry => !priceEntry.endDate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (activePriceIndex !== -1 && existingProduct.priceHistory[activePriceIndex].price != price) {
 | 
				
			||||||
 | 
					            existingProduct.priceHistory[activePriceIndex].endDate = new Date();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            return res.status(StatusCodes.BAD_REQUEST).json({
 | 
				
			||||||
 | 
					                msg: `Product with the same price ${price}`
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const newPriceEntry = {
 | 
				
			||||||
 | 
					        startDate: new Date(),
 | 
				
			||||||
 | 
					        endDate: null, // Novo preço ativo
 | 
				
			||||||
 | 
					        price
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (description) existingProduct.description = description.trim();
 | 
				
			||||||
 | 
					    if (name) existingProduct.name = name.trim();
 | 
				
			||||||
 | 
					    if (price) existingProduct.priceHistory.push(newPriceEntry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await existingProduct.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    res.status(StatusCodes.OK).json({
 | 
				
			||||||
 | 
					        msg: 'Preço do produto atualizado com sucesso!',
 | 
				
			||||||
 | 
					        product: existingProduct
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const setProductPricing = async (req, res) => {
 | 
				
			||||||
 | 
					    const { name, description, price } = req.body;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    console.log("price: ", price)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mustContainProperties(req, ['name']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const normalizedName = name.trim();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let existingProduct = await API_Products.findOne({ name: normalizedName });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (existingProduct) {
 | 
				
			||||||
 | 
					        if (price) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const activePriceIndex = existingProduct.priceHistory.findIndex(priceEntry => !priceEntry.endDate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (activePriceIndex !== -1 && existingProduct.priceHistory[activePriceIndex].price != price) {
 | 
				
			||||||
 | 
					                existingProduct.priceHistory[activePriceIndex].endDate = new Date();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                return res.status(StatusCodes.BAD_REQUEST).json({
 | 
				
			||||||
 | 
					                    msg: `Product with the same price ${price}`
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const newPriceEntry = {
 | 
				
			||||||
 | 
					                startDate: new Date(),
 | 
				
			||||||
 | 
					                endDate: null, // Novo preço ativo
 | 
				
			||||||
 | 
					                price
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            existingProduct.priceHistory.push(newPriceEntry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (description) existingProduct.description = description.trim();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            await existingProduct.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return res.status(StatusCodes.OK).json({
 | 
				
			||||||
 | 
					                msg: 'Preço do produto atualizado com sucesso!',
 | 
				
			||||||
 | 
					                product: existingProduct
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return res.status(StatusCodes.CONFLICT).json({
 | 
				
			||||||
 | 
					                error: 'Produto já existe. Para atualizar o preço, forneça o campo "price".',
 | 
				
			||||||
 | 
					                product: existingProduct
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Se o produto não existe, criar um novo
 | 
				
			||||||
 | 
					    const productData = {
 | 
				
			||||||
 | 
					        name: normalizedName,
 | 
				
			||||||
 | 
					        description: description?.trim() || '',
 | 
				
			||||||
 | 
					        priceHistory: []
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (price) {
 | 
				
			||||||
 | 
					        const priceEntry = {
 | 
				
			||||||
 | 
					            startDate: new Date(), // Data atual automática
 | 
				
			||||||
 | 
					            endDate: null, // Preço ativo (sem data de fim)
 | 
				
			||||||
 | 
					            price,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        productData.priceHistory.push(priceEntry);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    console.log('---------> Dados do produto a ser criado:', productData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Criar o produto
 | 
				
			||||||
 | 
					    const newProduct = new API_Products(productData);
 | 
				
			||||||
 | 
					    await newProduct.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    res.status(StatusCodes.CREATED).json({
 | 
				
			||||||
 | 
					        msg: 'Produto criado com sucesso!',
 | 
				
			||||||
 | 
					        product: newProduct
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const listProductPricing = async (req, res) => {
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					    const products = await API_Products.find();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    res.status(StatusCodes.OK).json({
 | 
				
			||||||
 | 
					        msg: 'ok', 
 | 
				
			||||||
 | 
					        products
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const registerUsage = async (req, res) => {
 | 
					const registerUsage = async (req, res) => {
 | 
				
			||||||
    const {
 | 
					    const {
 | 
				
			||||||
        provider,
 | 
					        provider,
 | 
				
			||||||
| 
						 | 
					@ -320,6 +461,9 @@ const getUsage = async (req, res) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = {
 | 
					module.exports = {
 | 
				
			||||||
    setApiPricing,
 | 
					    setApiPricing,
 | 
				
			||||||
 | 
					    setProductPricing,
 | 
				
			||||||
 | 
					    updateProductPricing,
 | 
				
			||||||
 | 
					    listProductPricing,
 | 
				
			||||||
    registerUsage,
 | 
					    registerUsage,
 | 
				
			||||||
    registerAPICall,
 | 
					    registerAPICall,
 | 
				
			||||||
    registerOperation,
 | 
					    registerOperation,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,55 @@
 | 
				
			||||||
 | 
					const mongoose = require('../db/connect');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { Schema } = mongoose;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @description Sub-schema para o histórico de preços.
 | 
				
			||||||
 | 
					 * A opção `strict: false` permite adicionar campos de preço dinâmicos (ex: tokenPrice, sttSecondPrice)
 | 
				
			||||||
 | 
					 * que podem variar conforme o `pricingModel` do produto principal.
 | 
				
			||||||
 | 
					 * A opção `_id: false` evita que o Mongoose crie um ObjectId para cada entrada no histórico.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const priceHistorySchema = new Schema({
 | 
				
			||||||
 | 
					    startDate: {
 | 
				
			||||||
 | 
					        type: Date,
 | 
				
			||||||
 | 
					        required: [true, 'A data de início da vigência é obrigatória.'],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    endDate: {
 | 
				
			||||||
 | 
					        type: Date,
 | 
				
			||||||
 | 
					        default: null, // Um valor nulo significa que o preço está atualmente vigente.
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // price: {
 | 
				
			||||||
 | 
					    //     type: String,
 | 
				
			||||||
 | 
					    //     required: [true, 'O preço é obrigatório'],
 | 
				
			||||||
 | 
					    // }
 | 
				
			||||||
 | 
					}, { _id: false, strict: false });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @description Schema principal para os produtos da API.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					const apiProductSchema = new Schema({
 | 
				
			||||||
 | 
					    name: {
 | 
				
			||||||
 | 
					        type: String,
 | 
				
			||||||
 | 
					        required: [true, 'O nome do produto é obrigatório.'],
 | 
				
			||||||
 | 
					        trim: true,
 | 
				
			||||||
 | 
					        unique: true, // Garante que não hajam produtos com o mesmo nome.
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    description: {
 | 
				
			||||||
 | 
					        type: String,
 | 
				
			||||||
 | 
					        trim: true,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    // pricingModel: {
 | 
				
			||||||
 | 
					    //     type: String,
 | 
				
			||||||
 | 
					    //     required: [true, 'O modelo de precificação é obrigatório.'],
 | 
				
			||||||
 | 
					    //     trim: true,
 | 
				
			||||||
 | 
					    // },
 | 
				
			||||||
 | 
					    priceHistory: {
 | 
				
			||||||
 | 
					        type: [priceHistorySchema],
 | 
				
			||||||
 | 
					        default: [], // O produto pode ser criado sem um histórico de preços inicial.
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					}, {
 | 
				
			||||||
 | 
					    timestamps: true, // Adiciona os campos `createdAt` e `updatedAt` automaticamente.
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					const API_Products = mongoose.model('API_Products', apiProductSchema);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = API_Products;
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,9 @@ const express = require('express')
 | 
				
			||||||
const router = express.Router()
 | 
					const router = express.Router()
 | 
				
			||||||
const { authorization, } = require('../middleware/authentication') 
 | 
					const { authorization, } = require('../middleware/authentication') 
 | 
				
			||||||
const { setApiPricing, 
 | 
					const { setApiPricing, 
 | 
				
			||||||
 | 
					    setProductPricing,
 | 
				
			||||||
 | 
					    updateProductPricing,
 | 
				
			||||||
 | 
					    listProductPricing,
 | 
				
			||||||
    registerUsage, 
 | 
					    registerUsage, 
 | 
				
			||||||
    getUsage, 
 | 
					    getUsage, 
 | 
				
			||||||
    registerAPICall, 
 | 
					    registerAPICall, 
 | 
				
			||||||
| 
						 | 
					@ -10,6 +13,9 @@ const { setApiPricing,
 | 
				
			||||||
registerWhatsappUsage} = require('../controllers/apiUsagePricing')
 | 
					registerWhatsappUsage} = require('../controllers/apiUsagePricing')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
router.route('/create').post(authorization, setApiPricing)  
 | 
					router.route('/create').post(authorization, setApiPricing)  
 | 
				
			||||||
 | 
					router.route('/create-product').post(authorization, setProductPricing)
 | 
				
			||||||
 | 
					router.route('/create-product').get(authorization, listProductPricing)
 | 
				
			||||||
 | 
					router.route('/create-product/:id').patch(authorization, updateProductPricing)
 | 
				
			||||||
router.route('/usage').post(authorization, registerUsage)
 | 
					router.route('/usage').post(authorization, registerUsage)
 | 
				
			||||||
router.route('/usage-whatsapp').post(authorization, registerWhatsappUsage)  
 | 
					router.route('/usage-whatsapp').post(authorization, registerWhatsappUsage)  
 | 
				
			||||||
router.route('/report').post(authorization, getUsage)  
 | 
					router.route('/report').post(authorization, getUsage)  
 | 
				
			||||||
| 
						 | 
					@ -17,6 +23,4 @@ router.route('/api-call').post(authorization, registerAPICall)
 | 
				
			||||||
router.route('/api-operation').post(authorization, registerOperation)  
 | 
					router.route('/api-operation').post(authorization, registerOperation)  
 | 
				
			||||||
router.route('/api-register-all').post(authorization, registerAll)  
 | 
					router.route('/api-register-all').post(authorization, registerAll)  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module.exports = router
 | 
					module.exports = router
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue