summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMateus Cruz <mateuscolvr@gmail.com>2024-02-05 20:39:19 -0300
committerMateus Cruz <mateuscolvr@gmail.com>2024-02-05 20:39:19 -0300
commit81e194d07f6ddd653b8bef4d50ba454df41c2702 (patch)
tree0d1e79bd0d42b2130d1745a278dee6b8c84d713a
parentb2aed14fd4a252d77b7ebaf42407472c47d1c98b (diff)
add debit logic
-rw-r--r--docker-compose.yml12
-rw-r--r--lib/client.ml1
-rw-r--r--lib/handler.ml32
-rw-r--r--lib/operation.ml40
-rw-r--r--lib/query.ml23
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