feat: Refactor code structure and optimize performance across multiple modules
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import 'package:graphql_flutter/graphql_flutter.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:krow/core/application/clients/api/api_client.dart';
|
||||
import 'package:krow/core/data/models/pagination_wrapper/pagination_wrapper.dart';
|
||||
|
||||
import 'invoices_gql.dart';
|
||||
import 'models/invoice_model.dart';
|
||||
|
||||
@Injectable()
|
||||
class InvoiceApiProvider {
|
||||
final ApiClient _client;
|
||||
|
||||
InvoiceApiProvider({required ApiClient client}) : _client = client;
|
||||
|
||||
Future<PaginationWrapper> fetchInvoices(String? status,
|
||||
{String? after}) async {
|
||||
final QueryResult result = await _client.query(
|
||||
schema: getInvoicesQuery,
|
||||
body: {
|
||||
if (status != null) 'status': status,
|
||||
'first': 20,
|
||||
'after': after
|
||||
});
|
||||
|
||||
if (result.hasException) {
|
||||
throw Exception(result.exception.toString());
|
||||
}
|
||||
return PaginationWrapper.fromJson(
|
||||
result.data!['client_invoices'], (json) => InvoiceModel.fromJson(json));
|
||||
}
|
||||
|
||||
Future<void>approveInvoice({required String invoiceId}) async{
|
||||
final QueryResult result = await _client.mutate(
|
||||
schema: approveInvoiceMutation,
|
||||
body: {
|
||||
'id': invoiceId,
|
||||
});
|
||||
|
||||
if (result.hasException) {
|
||||
throw Exception(result.exception.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> disputeInvoice({
|
||||
required String invoiceId,
|
||||
required String reason,
|
||||
required String comment,
|
||||
}) async {
|
||||
final QueryResult result = await _client.mutate(
|
||||
schema: disputeInvoiceMutation,
|
||||
body: {
|
||||
'id': invoiceId,
|
||||
'reason': reason,
|
||||
'comment': comment,
|
||||
});
|
||||
|
||||
if (result.hasException) {
|
||||
throw Exception(result.exception.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
const String getInvoicesQuery = '''
|
||||
query GetInvoices (\$status: InvoiceStatus, \$first: Int!, \$after: String) {
|
||||
client_invoices( status: \$status, first: \$first, after: \$after) {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
hasPreviousPage
|
||||
startCursor
|
||||
endCursor
|
||||
total
|
||||
count
|
||||
currentPage
|
||||
lastPage
|
||||
}
|
||||
edges {
|
||||
...invoice
|
||||
cursor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fragment invoice on InvoiceEdge {
|
||||
node {
|
||||
id
|
||||
business {
|
||||
id
|
||||
name
|
||||
avatar
|
||||
registration
|
||||
contact{
|
||||
id
|
||||
first_name
|
||||
last_name
|
||||
email
|
||||
phone
|
||||
}
|
||||
}
|
||||
event {
|
||||
id
|
||||
status
|
||||
start_time
|
||||
end_time
|
||||
contract_type
|
||||
...hub
|
||||
name
|
||||
date
|
||||
purchase_order
|
||||
}
|
||||
status
|
||||
contract_type
|
||||
contract_value
|
||||
total
|
||||
addons_amount
|
||||
work_amount
|
||||
issued_at
|
||||
due_at
|
||||
...items
|
||||
dispute {
|
||||
id
|
||||
reason
|
||||
details
|
||||
support_note
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment items on Invoice {
|
||||
items {
|
||||
id
|
||||
staff {
|
||||
id
|
||||
first_name
|
||||
last_name
|
||||
email
|
||||
phone
|
||||
address
|
||||
}
|
||||
position {
|
||||
id
|
||||
start_time
|
||||
end_time
|
||||
break
|
||||
count
|
||||
rate
|
||||
...business_skill
|
||||
staff{
|
||||
id
|
||||
pivot {
|
||||
id
|
||||
status
|
||||
start_at
|
||||
end_at
|
||||
clock_in
|
||||
clock_out
|
||||
}
|
||||
}
|
||||
}
|
||||
work_hours
|
||||
rate
|
||||
addons_amount
|
||||
work_amount
|
||||
total_amount
|
||||
}
|
||||
}
|
||||
|
||||
fragment business_skill on EventShiftPosition {
|
||||
business_skill {
|
||||
id
|
||||
skill {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
price
|
||||
is_active
|
||||
}
|
||||
}
|
||||
|
||||
fragment hub on Event {
|
||||
hub {
|
||||
id
|
||||
name
|
||||
full_address {
|
||||
formatted_address
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
''';
|
||||
|
||||
const String approveInvoiceMutation = '''
|
||||
mutation ApproveInvoice(\$id: ID!) {
|
||||
confirm_client_invoice(id: \$id) {
|
||||
id
|
||||
}
|
||||
}
|
||||
''';
|
||||
|
||||
const String disputeInvoiceMutation = '''
|
||||
mutation DisputeInvoice(\$id: ID!, \$reason: String!, \$comment: String!) {
|
||||
dispute_client_invoice(id: \$id, reason: \$reason, details: \$comment) {
|
||||
id
|
||||
}
|
||||
}
|
||||
''';
|
||||
@@ -0,0 +1,66 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:krow/features/invoice/data/invoices_api_provider.dart';
|
||||
import 'package:krow/features/invoice/domain/invoice_entity.dart';
|
||||
import 'package:krow/features/invoice/domain/invoices_repository.dart';
|
||||
|
||||
@Singleton(as: InvoicesRepository)
|
||||
class InvoicesRepositoryImpl extends InvoicesRepository {
|
||||
final InvoiceApiProvider _apiProvider;
|
||||
StreamController<InvoiceStatusFilterType>? _statusController;
|
||||
|
||||
InvoicesRepositoryImpl({required InvoiceApiProvider apiProvider})
|
||||
: _apiProvider = apiProvider;
|
||||
|
||||
@override
|
||||
Stream<InvoiceStatusFilterType> get statusStream {
|
||||
_statusController ??= StreamController<InvoiceStatusFilterType>.broadcast();
|
||||
return _statusController!.stream;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_statusController?.close();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<InvoiceListEntity>> getInvoices(
|
||||
{String? lastItemId,
|
||||
required InvoiceStatusFilterType statusFilter}) async {
|
||||
var paginationWrapper = await _apiProvider.fetchInvoices(
|
||||
statusFilter == InvoiceStatusFilterType.all ? null : statusFilter.name,
|
||||
after: lastItemId);
|
||||
return paginationWrapper.edges.map((e) {
|
||||
return InvoiceListEntity.fromModel(
|
||||
e.node,
|
||||
cursor: (paginationWrapper.pageInfo.hasNextPage) ? e.cursor : null,
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> approveInvoice({required String invoiceId}) async{
|
||||
await _apiProvider.approveInvoice(invoiceId: invoiceId).then((value) {
|
||||
_statusController?.add(InvoiceStatusFilterType.verified);
|
||||
});
|
||||
_statusController?.add(InvoiceStatusFilterType.all);
|
||||
_statusController?.add(InvoiceStatusFilterType.open);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> disputeInvoice({
|
||||
required String invoiceId,
|
||||
required String reason,
|
||||
required String comment,
|
||||
}) async {
|
||||
await _apiProvider.disputeInvoice(
|
||||
invoiceId: invoiceId,
|
||||
reason: reason,
|
||||
comment: comment,
|
||||
);
|
||||
_statusController?.add(InvoiceStatusFilterType.disputed);
|
||||
_statusController?.add(InvoiceStatusFilterType.all);
|
||||
_statusController?.add(InvoiceStatusFilterType.open);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'invoice_decline_model.g.dart';
|
||||
|
||||
@JsonSerializable(fieldRename: FieldRename.snake)
|
||||
class InvoiceDeclineModel{
|
||||
String id;
|
||||
String? reason;
|
||||
String? details;
|
||||
String? supportNote;
|
||||
|
||||
InvoiceDeclineModel({
|
||||
required this.id,
|
||||
required this.reason,
|
||||
this.details,
|
||||
this.supportNote,
|
||||
});
|
||||
factory InvoiceDeclineModel.fromJson(Map<String, dynamic> json) {
|
||||
return _$InvoiceDeclineModelFromJson(json);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => _$InvoiceDeclineModelToJson(this);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:krow/core/data/models/shift/event_shift_position_model.dart';
|
||||
import 'package:krow/core/data/models/staff/staff_model.dart';
|
||||
import 'package:krow/core/entity/staff_contact_entity.dart';
|
||||
import 'package:krow/features/events/presentation/event_details/widgets/role/asigned_staff.dart';
|
||||
|
||||
part 'invoice_item_model.g.dart';
|
||||
|
||||
@JsonSerializable(fieldRename: FieldRename.snake)
|
||||
class InvoiceItemModel {
|
||||
final String id;
|
||||
final StaffModel? staff;
|
||||
final EventShiftPositionModel? position;
|
||||
final double? workHours;
|
||||
final double? rate;
|
||||
final double? addonsAmount;
|
||||
final double? workAmount;
|
||||
final double? totalAmount;
|
||||
|
||||
InvoiceItemModel(
|
||||
{required this.id,
|
||||
required this.staff,
|
||||
required this.position,
|
||||
required this.workHours,
|
||||
required this.rate,
|
||||
required this.addonsAmount,
|
||||
required this.workAmount,
|
||||
required this.totalAmount});
|
||||
|
||||
factory InvoiceItemModel.fromJson(Map<String, dynamic> json) {
|
||||
return _$InvoiceItemModelFromJson(json);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => _$InvoiceItemModelToJson(this);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:krow/core/data/models/event/business_model.dart';
|
||||
import 'package:krow/core/data/models/event/event_model.dart';
|
||||
import 'package:krow/features/invoice/data/models/invoice_decline_model.dart';
|
||||
import 'package:krow/features/invoice/data/models/invoice_item_model.dart';
|
||||
|
||||
part 'invoice_model.g.dart';
|
||||
|
||||
enum InvoiceStatus { open, disputed, resolved, paid, overdue, verified }
|
||||
|
||||
@JsonSerializable(fieldRename: FieldRename.snake)
|
||||
class InvoiceModel {
|
||||
final String id;
|
||||
final InvoiceStatus status;
|
||||
final BusinessModel? business;
|
||||
final EventModel? event;
|
||||
final String? contractType;
|
||||
final String? contractValue;
|
||||
final String? dueAt;
|
||||
final double? total;
|
||||
final double? addonsAmount;
|
||||
final double? workAmount;
|
||||
final List<InvoiceItemModel>? items;
|
||||
final InvoiceDeclineModel? dispute;
|
||||
|
||||
factory InvoiceModel.fromJson(Map<String, dynamic> json) {
|
||||
return _$InvoiceModelFromJson(json);
|
||||
}
|
||||
|
||||
InvoiceModel(
|
||||
{required this.id,
|
||||
required this.status,
|
||||
required this.business,
|
||||
required this.event,
|
||||
required this.contractType,
|
||||
required this.contractValue,
|
||||
required this.total,
|
||||
required this.addonsAmount,
|
||||
required this.dueAt,
|
||||
required this.workAmount,
|
||||
required this.items,
|
||||
required this.dispute});
|
||||
|
||||
Map<String, dynamic> toJson() => _$InvoiceModelToJson(this);
|
||||
|
||||
copyWith({
|
||||
String? id,
|
||||
InvoiceStatus? status,
|
||||
BusinessModel? business,
|
||||
EventModel? event,
|
||||
String? contractType,
|
||||
String? contractValue,
|
||||
String? dueAt,
|
||||
double? total,
|
||||
double? addonsAmount,
|
||||
double? workAmount,
|
||||
List<InvoiceItemModel>? items,
|
||||
InvoiceDeclineModel? dispute,
|
||||
}) {
|
||||
return InvoiceModel(
|
||||
id: id ?? this.id,
|
||||
status: status ?? this.status,
|
||||
business: business ?? this.business,
|
||||
event: event ?? this.event,
|
||||
contractType: contractType ?? this.contractType,
|
||||
contractValue: contractValue ?? this.contractValue,
|
||||
total: total ?? this.total,
|
||||
addonsAmount: addonsAmount ?? this.addonsAmount,
|
||||
workAmount: workAmount ?? this.workAmount,
|
||||
items: items ?? this.items,
|
||||
dueAt: dueAt ?? this.dueAt,
|
||||
dispute: dispute ?? this.dispute,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user