Files
EventHubBack/src/core/core_ticket.erl

106 lines
3.6 KiB
Erlang

-module(core_ticket).
-include("records.hrl").
-export([list_all/0,
get_by_id/1,
update_ticket/2,
delete_ticket/1,
stats/0,
create_ticket/1,
list_by_user/1]).
-export([count_tickets_by_status/1, count_tickets_by_admin/2]).
-export([avg_resolution_time/0]).
list_all() ->
mnesia:dirty_match_object(#ticket{_ = '_'}).
get_by_id(Id) ->
case mnesia:dirty_read({ticket, Id}) of
[Ticket] -> {ok, Ticket};
[] -> {error, not_found}
end.
update_ticket(Id, Updates) ->
case get_by_id(Id) of
{ok, Ticket} ->
Updated = apply_updates(Ticket, Updates),
mnesia:dirty_write(Updated),
{ok, Updated};
Error -> Error
end.
delete_ticket(Id) ->
case get_by_id(Id) of
{ok, _Ticket} -> % переменная не используется
mnesia:dirty_delete({ticket, Id}),
{ok, deleted};
Error -> Error
end.
stats() ->
Tickets = list_all(),
#{
total => length(Tickets),
open => count_by_status(open, Tickets),
in_progress => count_by_status(in_progress, Tickets),
resolved => count_by_status(resolved, Tickets),
closed => count_by_status(closed, Tickets)
}.
%% ── новые функции ──────────────────────────────────────
create_ticket(Data) ->
Id = base64:encode(crypto:strong_rand_bytes(9), #{mode => urlsafe, padding => false}),
Now = calendar:universal_time(),
Ticket = #ticket{
id = Id,
reporter_id = maps:get(<<"reporter_id">>, Data, undefined),
error_hash = maps:get(<<"error_hash">>, Data, <<"">>),
error_message = maps:get(<<"error_message">>, Data),
stacktrace = maps:get(<<"stacktrace">>, Data, <<"">>),
context = maps:get(<<"context">>, Data, <<"">>),
count = 1,
first_seen = Now,
last_seen = Now,
status = maps:get(<<"status">>, Data, open),
assigned_to = maps:get(<<"assigned_to">>, Data, undefined),
resolution_note = maps:get(<<"resolution_note">>, Data, undefined)
},
mnesia:dirty_write(Ticket),
{ok, Ticket}.
list_by_user(UserId) ->
mnesia:dirty_match_object(#ticket{reporter_id = UserId, _ = '_'}).
count_by_status(Status, Tickets) ->
length([T || T <- Tickets, T#ticket.status =:= Status]).
count_tickets_by_status(Status) ->
Match = #ticket{status = Status, _ = '_'},
length(mnesia:dirty_match_object(Match)).
count_tickets_by_admin(AdminId, Status) ->
Match = #ticket{assigned_to = AdminId, status = Status, _ = '_'},
length(mnesia:dirty_match_object(Match)).
avg_resolution_time() ->
Tickets = mnesia:dirty_match_object(#ticket{status = closed, _ = '_'}),
case Tickets of
[] -> 0;
_ ->
TotalSeconds = lists:sum([calendar:datetime_to_gregorian_seconds(T#ticket.last_seen) -
calendar:datetime_to_gregorian_seconds(T#ticket.first_seen) || T <- Tickets]),
TotalSeconds / length(Tickets) / 3600.0
end.
%% ── внутренние ─────────────────────────────────────────
apply_updates(Ticket, Updates) ->
lists:foldl(fun({Key, Value}, Acc) ->
case Key of
<<"status">> -> Acc#ticket{status = binary_to_atom(Value, utf8)};
<<"assigned_to">> -> Acc#ticket{assigned_to = Value};
<<"resolution_note">> -> Acc#ticket{resolution_note = Value};
<<"error_message">> -> Acc#ticket{error_message = Value};
<<"stacktrace">> -> Acc#ticket{stacktrace = Value};
<<"context">> -> Acc#ticket{context = Value};
_ -> Acc
end
end, Ticket, maps:to_list(Updates)).