diff options
author | Mateus Cruz <mateuscolvr@gmail.com> | 2024-02-05 20:39:19 -0300 |
---|---|---|
committer | Mateus Cruz <mateuscolvr@gmail.com> | 2024-02-05 20:39:19 -0300 |
commit | 81e194d07f6ddd653b8bef4d50ba454df41c2702 (patch) | |
tree | 0d1e79bd0d42b2130d1745a278dee6b8c84d713a | |
parent | b2aed14fd4a252d77b7ebaf42407472c47d1c98b (diff) |
add debit logic
-rw-r--r-- | docker-compose.yml | 12 | ||||
-rw-r--r-- | lib/client.ml | 1 | ||||
-rw-r--r-- | lib/handler.ml | 32 | ||||
-rw-r--r-- | lib/operation.ml | 40 | ||||
-rw-r--r-- | lib/query.ml | 23 |
5 files changed, 63 insertions, 45 deletions
diff --git a/docker-compose.yml b/docker-compose.yml index ccf1661..eb90487 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -35,7 +35,6 @@ services: db: image: postgres:latest - hostname: db environment: - POSTGRES_PASSWORD=123 - POSTGRES_USER=admin @@ -49,14 +48,3 @@ services: limits: cpus: "0.63" memory: "140MB" - - pgadmin: - image: dpage/pgadmin4 - environment: - PGADMIN_DEFAULT_EMAIL: admin@admin.com - PGADMIN_DEFAULT_PASSWORD: admin - PGADMIN_LISTEN_PORT: 5050 - ports: - - 5050:5050 - depends_on: - - db diff --git a/lib/client.ml b/lib/client.ml index 80a11b7..8be4644 100644 --- a/lib/client.ml +++ b/lib/client.ml @@ -1,4 +1,5 @@ type t = { id : int ; mov_limit : int + ; balance : int } diff --git a/lib/handler.ml b/lib/handler.ml index a4d8cae..fb075ff 100644 --- a/lib/handler.ml +++ b/lib/handler.ml @@ -1,5 +1,10 @@ open Piaf +let valid_debit value limit balance = + let balance_after_op = balance - value in + not (balance_after_op <= limit * -1) +;; + let create_transaction client_id (db_pool : Query.pool) (request : Request.t) = Caqti_eio.Pool.use (fun conn -> @@ -7,22 +12,35 @@ let create_transaction client_id (db_pool : Query.pool) (request : Request.t) = Option.join @@ Result.to_option @@ Query.find_client client_id conn in match client_opt with - | Some _client -> + | Some client -> let insert_result = let body = Result.to_option @@ Body.to_string request.body in - let json = Option.map Yojson.Safe.from_string body in + let json = + Option.map + (fun str -> + try Yojson.Safe.from_string str with + | _ -> `Null) + body + in let decoded_op = Option.bind json (Utils.Decoder.decode Operation.decoder) in match decoded_op with - | Some op -> - (match Query.execute_operation ~client_id ~op conn with + | Some (`Credit { value = _value; description = _desc } as op) -> + (match Query.execute_transaction ~client_id ~op conn with | Ok _ as ok -> ok | Error e -> Error (`DB e)) + | Some (`Debit { value; description = _desc } as op) -> + if valid_debit value client.mov_limit client.balance + then ( + match Query.execute_transaction ~client_id ~op conn with + | Ok _ as ok -> ok + | Error e -> Error (`DB e)) + else Error `InvalidValue | None -> Error (`Decoder "Invalid operation") in (match insert_result with | Ok () -> let json : Yojson.Safe.t = - `Assoc [ "limite", `Int 100000; "saldo", `Int (-9098) ] + `Assoc [ "limite", `Int client.mov_limit; "saldo", `Int client.balance ] in Ok (Response.of_string ~body:(Yojson.Safe.to_string json) `OK) | Error _ -> Ok (Response.create (`Code 422))) @@ -39,7 +57,7 @@ let get_balance client_id (db_pool : Query.pool) (_request : Request.t) = Option.join @@ Result.to_option @@ Query.find_client client_id conn in match client_opt with - | Some _client -> + | Some client -> let client_balance_opt = Option.join @@ Result.to_option @@ Query.balance client_id conn in @@ -52,7 +70,7 @@ let get_balance client_id (db_pool : Query.pool) (_request : Request.t) = `String (Format.asprintf "%a" (Ptime.pp_rfc3339 ~tz_offset_s:(-10800) ()) time) in - let limit = `Int 100000 in + let limit = `Int client.mov_limit in `Assoc [ "total", total; "data_extrato", date; "limite", limit ] in let last_transactions = `List [] in diff --git a/lib/operation.ml b/lib/operation.ml index 1fb1dd5..3c8df2a 100644 --- a/lib/operation.ml +++ b/lib/operation.ml @@ -1,29 +1,34 @@ module TransactionType = struct type t = - | Credit - | Debit + [ `Credit + | `Debit + ] let t = let encode = function - | Credit -> "credit" - | Debit -> "debit" + | `Credit -> "credit" + | `Debit -> "debit" in let decode = function - | "credit" -> Ok Credit - | "debit" -> Ok Debit + | "credit" -> Ok `Credit + | "debit" -> Ok `Debit | _ -> Error "Invalid transaction type" in Caqti_type.(enum ~encode ~decode "transaction_type") ;; end -type t = - | Transaction of - { transaction_type : TransactionType.t - ; value : int - ; description : string - } - | Balance of { client_id : int } +type transaction_payload = + { value : int + ; description : string + } + +type transaction_op = + [ `Credit of transaction_payload + | `Debit of transaction_payload + ] + +type t = Balance of { client_id : int } type transaction = { id : int @@ -34,15 +39,14 @@ type transaction = ; created_at : Ptime.t } -let decoder = +let decoder : transaction_op Utils.Decoder.decoder = let open Utils.Decoder in let open Syntax in let transaction_type_decoder = - literal "c" *> return TransactionType.Credit - <|> literal "d" *> return TransactionType.Debit + literal "c" *> return (fun p -> `Credit p) + <|> literal "d" *> return (fun p -> `Debit p) in - (fun value transaction_type description -> - Transaction { value; description; transaction_type }) + (fun value transaction_type description -> transaction_type { value; description }) <$> ("valor" <: int) <*> ("tipo" <: transaction_type_decoder) <*> ("descricao" <: string) diff --git a/lib/query.ml b/lib/query.ml index 85f91f0..6e359ce 100644 --- a/lib/query.ml +++ b/lib/query.ml @@ -31,7 +31,9 @@ module Q = struct [%rapper get_opt {sql| - SELECT @int{id}, @int{mov_limit} FROM clients WHERE id = %int{id} + SELECT clients.id as @int{id}, @int{mov_limit}, value as @int{balance} FROM clients + JOIN balances ON balances.client_id = %int{id} + WHERE clients.id = %int{id} |sql} record_out] ;; @@ -47,14 +49,19 @@ end let ( let* ) = Result.bind -let execute_operation ~client_id ~(op : Operation.t) conn = +(* TODO: Separar em duas funções *) +let execute_transaction ~client_id ~(op : Operation.transaction_op) conn = match op with - | Transaction { value; description; transaction_type } -> - let* () = Q.transaction ~client_id ~value ~description conn ~transaction_type in - (match transaction_type with - | Credit -> Q.credit ~value ~client_id conn - | Debit -> Q.debit ~value ~client_id conn) - | _ -> failwith "TODO" + | `Credit { value; description } -> + let* () = + Q.transaction ~client_id ~value ~description conn ~transaction_type:`Credit + in + Q.credit ~value ~client_id conn + | `Debit { value; description } -> + let* () = + Q.transaction ~client_id ~value ~description conn ~transaction_type:`Debit + in + Q.debit ~value ~client_id conn ;; let find_client id conn = Q.client ~id conn |