Implement tender workflows and dashboard integration
continuous-integration/drone/push Build encountered an error

This commit is contained in:
AmirReza Jamali
2026-07-14 11:12:09 +03:30
parent ce170f9bc8
commit 72881df210
29 changed files with 1820 additions and 159 deletions
@@ -0,0 +1,235 @@
import 'package:tm_app/core/utils/date_utils.dart';
import 'package:tm_app/data/services/model/tender_data/tender_data.dart';
class TenderSubmissionResponse {
const TenderSubmissionResponse({
required this.success,
required this.message,
required this.data,
});
final bool success;
final String? message;
final TenderSubmission? data;
factory TenderSubmissionResponse.fromJson(Map<String, dynamic> json) {
final data = json['data'];
return TenderSubmissionResponse(
success: json['success'] == true,
message: json['message'] as String?,
data:
data is Map<String, dynamic> ? TenderSubmission.fromJson(data) : null,
);
}
}
class TenderSubmissionsResponse {
const TenderSubmissionsResponse({
required this.success,
required this.message,
required this.data,
required this.meta,
});
final bool success;
final String? message;
final List<TenderSubmission> data;
final TenderSubmissionsMeta? meta;
factory TenderSubmissionsResponse.fromJson(Map<String, dynamic> json) {
final items = json['data'];
return TenderSubmissionsResponse(
success: json['success'] == true,
message: json['message'] as String?,
data:
items is List
? items
.whereType<Map>()
.map(
(item) => TenderSubmission.fromJson(
Map<String, dynamic>.from(item),
),
)
.toList()
: const [],
meta:
json['meta'] is Map
? TenderSubmissionsMeta.fromJson(
Map<String, dynamic>.from(json['meta'] as Map),
)
: null,
);
}
}
class TenderSubmission {
const TenderSubmission({
required this.id,
required this.tenderId,
required this.companyId,
required this.customerId,
required this.status,
required this.stage,
required this.submissionMode,
required this.statusHistory,
required this.createdAt,
required this.updatedAt,
required this.tender,
});
final String id;
final String tenderId;
final String? companyId;
final String? customerId;
final String status;
final String stage;
final String? submissionMode;
final List<TenderSubmissionHistory> statusHistory;
final int? createdAt;
final int? updatedAt;
final TenderData? tender;
bool get isTerminal =>
status == 'rejected' || status == 'contract' || status == 'not_applied';
factory TenderSubmission.fromJson(Map<String, dynamic> json) {
final history = json['status_history'];
final tenderJson = json['tender'];
return TenderSubmission(
id: json['id']?.toString() ?? '',
tenderId: json['tender_id']?.toString() ?? '',
companyId: json['company_id']?.toString(),
customerId: json['customer_id']?.toString(),
status: json['status']?.toString() ?? 'opportunity',
stage: json['stage']?.toString() ?? 'opportunity',
submissionMode: json['submission_mode']?.toString(),
statusHistory:
history is List
? history
.whereType<Map>()
.map(
(item) => TenderSubmissionHistory.fromJson(
Map<String, dynamic>.from(item),
),
)
.toList()
: const [],
createdAt: unixTimestampFromJson(json['created_at']),
updatedAt: unixTimestampFromJson(json['updated_at']),
tender:
tenderJson is Map
? TenderData.fromJson(Map<String, dynamic>.from(tenderJson))
: null,
);
}
}
class TenderSubmissionHistory {
const TenderSubmissionHistory({
required this.status,
required this.reason,
required this.changedBy,
required this.changedAt,
required this.description,
});
final String status;
final String? reason;
final String? changedBy;
final int? changedAt;
final String? description;
factory TenderSubmissionHistory.fromJson(Map<String, dynamic> json) {
return TenderSubmissionHistory(
status: json['status']?.toString() ?? '',
reason: json['reason']?.toString(),
changedBy: json['changed_by']?.toString(),
changedAt: unixTimestampFromJson(json['changed_at']),
description: json['description']?.toString(),
);
}
}
class TenderSubmissionsMeta {
const TenderSubmissionsMeta({
required this.total,
required this.limit,
required this.offset,
required this.page,
required this.pages,
required this.hasMore,
});
final int total;
final int limit;
final int offset;
final int page;
final int pages;
final bool hasMore;
factory TenderSubmissionsMeta.fromJson(Map<String, dynamic> json) {
int number(String key) => (json[key] as num?)?.toInt() ?? 0;
return TenderSubmissionsMeta(
total: number('total'),
limit: number('limit'),
offset: number('offset'),
page: number('page'),
pages: number('pages'),
hasMore: json['has_more'] == true,
);
}
}
class TenderSubmissionStatsResponse {
const TenderSubmissionStatsResponse({
required this.success,
required this.data,
});
final bool success;
final TenderSubmissionStats? data;
factory TenderSubmissionStatsResponse.fromJson(Map<String, dynamic> json) {
return TenderSubmissionStatsResponse(
success: json['success'] == true,
data:
json['data'] is Map
? TenderSubmissionStats.fromJson(
Map<String, dynamic>.from(json['data'] as Map),
)
: null,
);
}
}
class TenderSubmissionStats {
const TenderSubmissionStats({
required this.companyId,
required this.total,
required this.byStage,
required this.byStatus,
required this.lastUpdated,
});
final String? companyId;
final int total;
final Map<String, int> byStage;
final Map<String, int> byStatus;
final int? lastUpdated;
factory TenderSubmissionStats.fromJson(Map<String, dynamic> json) {
Map<String, int> counts(value) =>
value is Map
? value.map(
(key, value) => MapEntry(key.toString(), (value as num).toInt()),
)
: const {};
return TenderSubmissionStats(
companyId: json['company_id']?.toString(),
total: (json['total'] as num?)?.toInt() ?? 0,
byStage: counts(json['by_stage']),
byStatus: counts(json['by_status']),
lastUpdated: unixTimestampFromJson(json['last_updated']),
);
}
}