2023-09-22 11:38:32 +02:00
package contract
import (
"errors"
2023-10-16 05:44:09 +02:00
"fmt"
2023-09-22 11:38:32 +02:00
"log"
"net/http"
"time"
"github.com/jinzhu/gorm"
2023-09-27 19:20:44 +02:00
"github.com/lib/pq"
2023-10-16 05:44:09 +02:00
"gitlab.com/pactual1/backend/database/device"
2023-09-22 11:38:32 +02:00
"gitlab.com/pactual1/backend/models"
"gitlab.com/pactual1/backend/shared"
)
2023-10-06 10:47:26 +02:00
func GetContracts ( status [ ] string , companyName string , companyAddress string ,
2023-10-03 18:26:57 +02:00
companyEmail string , companyPhone string , startTime * time . Time , endTime * time . Time ,
2023-10-13 11:48:14 +02:00
contractName string , deviceIDs [ ] int64 , contractIDs [ ] int64 , dateCreated * time . Time , limit , offset int ) ( [ ] models . Contract , int64 , int , error ) {
2023-10-03 18:26:57 +02:00
var contracts [ ] models . Contract
db := shared . GetDb ( )
countDb := db
// Define custom fields to be selected, varies based on joined tables
2023-10-13 11:48:14 +02:00
customFields := "distinct contracts.*, array_length(contracts.device_ids, 1) as number_of_devices"
2023-10-03 18:26:57 +02:00
2023-10-06 10:47:26 +02:00
// Search by Statuses
if len ( status ) > 0 {
db = db . Where ( "contracts.status IN (?)" , status )
countDb = countDb . Where ( "contracts.status IN (?)" , status )
2023-10-03 18:26:57 +02:00
}
2023-10-13 11:48:14 +02:00
// Search by IDs
if len ( contractIDs ) > 0 {
db = db . Where ( "contracts.id IN (?)" , contractIDs )
countDb = countDb . Where ( "contracts.id IN (?)" , contractIDs )
}
2023-10-03 18:26:57 +02:00
// Search by Company Fields
db = db . Joins ( "left join companies on companies.id = contracts.buyer_id" )
countDb = countDb . Joins ( "left join companies on companies.id = contracts.buyer_id" )
customFields += ", companies.name as buyer_name"
if companyName != "" {
db = db . Where ( "companies.name LIKE ?" , "%" + companyName + "%" )
countDb = countDb . Where ( "companies.name LIKE ?" , "%" + companyName + "%" )
}
if companyAddress != "" {
db = db . Where ( "companies.address LIKE ?" , "%" + companyAddress + "%" )
countDb = countDb . Where ( "companies.address LIKE ?" , "%" + companyAddress + "%" )
}
if companyEmail != "" {
db = db . Where ( "companies.email LIKE ?" , "%" + companyEmail + "%" )
countDb = countDb . Where ( "companies.email LIKE ?" , "%" + companyEmail + "%" )
}
if companyPhone != "" {
db = db . Where ( "companies.phone LIKE ?" , "%" + companyPhone + "%" )
countDb = countDb . Where ( "companies.phone LIKE ?" , "%" + companyPhone + "%" )
}
// Search by Contract Name
2023-09-27 19:20:44 +02:00
if contractName != "" {
db = db . Where ( "contracts.name LIKE ?" , "%" + contractName + "%" )
countDb = countDb . Where ( "contracts.name LIKE ?" , "%" + contractName + "%" )
2023-09-22 11:38:32 +02:00
}
2023-09-27 19:20:44 +02:00
2023-10-03 18:26:57 +02:00
// Search by Start Time and End Time
2023-10-13 11:48:14 +02:00
if startTime != nil && ! startTime . IsZero ( ) {
2023-10-03 18:26:57 +02:00
db = db . Where ( "start_time >= ?" , startTime )
countDb = countDb . Where ( "start_time >= ?" , startTime )
}
if endTime != nil && ! startTime . IsZero ( ) {
db = db . Where ( "end_time <= ?" , endTime )
countDb = countDb . Where ( "end_time <= ?" , endTime )
}
if dateCreated != nil && ! dateCreated . IsZero ( ) {
db = db . Where ( "contracts.created_at = ?" , dateCreated )
2023-10-13 11:48:14 +02:00
countDb = countDb . Where ( "contracts.created_at = ?" , dateCreated )
2023-10-03 18:26:57 +02:00
}
2023-09-27 19:20:44 +02:00
2023-10-03 18:26:57 +02:00
// Search by Device IDs
if len ( deviceIDs ) > 0 {
2023-09-27 19:20:44 +02:00
db = db . Where ( "device_ids && ?" , pq . Array ( deviceIDs ) )
countDb = countDb . Where ( "device_ids && ?" , pq . Array ( deviceIDs ) )
2023-10-03 18:26:57 +02:00
}
// Fetch total count of filtered records
var total int64
if err := countDb . Model ( & models . Contract { } ) . Count ( & total ) . Error ; err != nil {
log . Printf ( "GetContracts Error: Database error: %v" , err )
return contracts , total , http . StatusInternalServerError , err
}
// Fetch contracts with custom fields
if err := db . Select ( customFields ) .
Order ( "created_at desc" ) .
Limit ( limit ) .
Offset ( offset ) .
Find ( & contracts ) . Error ; err != nil {
if errors . Is ( err , gorm . ErrRecordNotFound ) {
log . Printf ( "GetContracts Error: No contracts found: %v" , err )
return contracts , total , http . StatusNotFound , err
} else {
log . Printf ( "GetContracts Error: Database error: %v" , err )
return contracts , total , http . StatusInternalServerError , err
}
}
return contracts , total , http . StatusOK , nil
2023-09-22 11:38:32 +02:00
}
2023-10-10 08:39:50 +02:00
func UpdateContract ( contract models . Contract ) ( models . Contract , int , error ) {
2023-10-16 05:44:09 +02:00
var devices [ ] models . Device
var status int
var err error
if contract . DeviceIDs != nil {
devices , status , err = device . GetDevicesByID ( contract . DeviceIDs )
if err != nil {
return contract , status , err
}
status , err = validateContractDevices ( contract . ID , devices )
if err != nil {
log . Printf ( "UpdateContract Error: Invalid Device ID: %v" , err )
return contract , status , err
}
}
err = shared . GetDb ( ) . Transaction ( func ( tx * gorm . DB ) error {
// Update contract
if err := tx . Model ( contract ) . Updates ( contract ) . Error ; err != nil {
log . Printf ( "UpdateContract Error: Could not update contract: %v" , err )
return err
}
if devices != nil {
// Update devices
if err := tx . Model ( models . Device { } ) . Where ( "id IN (?)" , contract . DeviceIDs ) . Updates ( models . Device { CurrentContractID : & contract . ID } ) . Error ; err != nil {
log . Printf ( "UpdateContract Error: Could not update devices: %v" , err )
return err
}
}
2023-09-22 11:38:32 +02:00
2023-10-16 05:44:09 +02:00
// return nil will commit the whole transaction
return nil
} )
if err != nil {
log . Printf ( "UpdateContract Error: Could not update contract: %v" , err )
2023-10-10 08:39:50 +02:00
return contract , http . StatusInternalServerError , err
}
2023-09-22 11:38:32 +02:00
2023-10-10 08:39:50 +02:00
return GetContractByID ( uint64 ( contract . ID ) )
2023-10-16 05:44:09 +02:00
}
func validateContractDevices ( contractID uint , devices [ ] models . Device ) ( int , error ) {
2023-09-27 19:20:44 +02:00
2023-10-16 05:44:09 +02:00
for _ , device := range devices {
if device . CurrentContractID != nil && * device . CurrentContractID != contractID {
currentDeviceContract , status , err := GetContractByID ( uint64 ( * device . CurrentContractID ) )
if err != nil {
return status , err
}
if currentDeviceContract . Status != models . ContractStatusExecuted &&
currentDeviceContract . Status == models . ContractStatusRevoked {
return http . StatusBadRequest , fmt . Errorf ( "device id %d is linked to contract id - %d name %s" , device . ID , currentDeviceContract . ID , currentDeviceContract . Name )
}
}
}
return http . StatusOK , nil
2023-10-10 08:39:50 +02:00
}
func GetContractByID ( contractID uint64 ) ( models . Contract , int , error ) {
2023-09-22 11:38:32 +02:00
// Fetch the contract creation date based on contractID
var contract models . Contract
2023-10-16 05:44:09 +02:00
if err := shared . GetDb ( ) . Unscoped ( ) . Where ( "id = ?" , contractID ) . First ( & contract ) . Error ; err != nil {
2023-10-10 08:39:50 +02:00
log . Printf ( "GetContractByID Error: Could not fetch contract: %v" , err )
2023-09-22 11:38:32 +02:00
return contract , http . StatusInternalServerError , err
}
2023-10-10 08:39:50 +02:00
return contract , http . StatusOK , nil
2023-09-22 11:38:32 +02:00
2023-10-16 05:44:09 +02:00
}