Refactor tender detail models and UI components for improved clarity and functionality

- Updated the `Lot`, `Organization`, and `OrganizationAddress` models to enhance data mapping for tender details.
- Revised the `TenderData` model to include additional fields reflecting the API response structure.
- Improved UI components across desktop, mobile, and tablet views by commenting out unused sections for future use.
- Added new string constants for lot details in the tender information section.
- Enhanced unit tests to cover new model fields and ensure resilience to partial API payloads.
This commit is contained in:
AmirReza Jamali
2026-06-05 19:42:09 +03:30
parent dde66521f6
commit 86ed7bc665
17 changed files with 204 additions and 375 deletions
-4
View File
@@ -51,10 +51,6 @@ void main() {
expect(feedback.tender?.buyerOrganization?.name, 'Buyer Org');
});
// AI-NOTE (for PR reviewer): These TenderData/Organization literals were
// updated only to satisfy the new required fields added to those models
// (notice_type_code, form_type, issue_date/time, lots, official_languages,
// company_id, address). Test assertions/behavior are unchanged.
test('toJson should return valid JSON map', () {
final tender = const TenderData(
success: true,
+158
View File
@@ -0,0 +1,158 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:tm_app/data/services/model/lot/lot.dart';
import 'package:tm_app/data/services/model/organization/organization.dart';
import 'package:tm_app/data/services/model/organization/organization_address.dart';
import 'package:tm_app/data/services/model/tender_data/tender_data.dart';
void main() {
group('Lot', () {
test('fromJson maps lot_id/title/description', () {
final lot = Lot.fromJson(const {
'lot_id': 'LOT-1',
'title': 'Lot title',
'description': 'Lot description',
});
expect(lot.lotId, 'LOT-1');
expect(lot.title, 'Lot title');
expect(lot.description, 'Lot description');
});
test('toJson round-trips back to the same values', () {
const lot = Lot(lotId: 'LOT-2', title: 'T', description: 'D');
expect(Lot.fromJson(lot.toJson()), lot);
});
test('missing fields parse as null (resilient to partial payloads)', () {
final lot = Lot.fromJson(const {});
expect(lot.lotId, isNull);
expect(lot.title, isNull);
expect(lot.description, isNull);
});
});
group('OrganizationAddress', () {
test('fromJson maps city_name/country_code', () {
final address = OrganizationAddress.fromJson(const {
'city_name': 'Amsterdam',
'country_code': 'NL',
});
expect(address.cityName, 'Amsterdam');
expect(address.countryCode, 'NL');
});
test('toJson round-trips back to the same values', () {
const address = OrganizationAddress(
cityName: 'Berlin',
countryCode: 'DE',
);
expect(OrganizationAddress.fromJson(address.toJson()), address);
});
test('nested under Organization.fromJson', () {
final org = Organization.fromJson(const {
'name': 'Buyer Org',
'company_id': 'COMP-1',
'address': {'city_name': 'Paris', 'country_code': 'FR'},
});
expect(org.name, 'Buyer Org');
expect(org.companyId, 'COMP-1');
expect(org.address?.cityName, 'Paris');
expect(org.address?.countryCode, 'FR');
});
});
group('TenderData new fields', () {
Map<String, Object?> baseJson({
Object? issueDate,
Object? issueTime,
}) => {
'success': true,
'message': 'ok',
'id': 'TND-1',
'tender_id': 'TND-1',
'notice_publication_id': 'NP-1',
'notice_type_code': 'NT-1',
'form_type': 'open',
'notice_language_code': 'en',
'issue_date': issueDate,
'issue_time': issueTime,
'publication_date': 1700000000,
'title': 'Title',
'description': 'Desc',
'procurement_type_code': 'PT-1',
'procedure_code': 'PRC-1',
'estimated_value': 1000,
'currency': 'EUR',
'duration': '12',
'tender_deadline': 1710000000,
'submission_deadline': 1710000000,
'application_deadline': 1710000000,
'submission_url': 'https://example.com',
'country_code': 'NL',
'duration_unit': 'month',
'buyer_organization': {
'name': 'Buyer Org',
'company_id': 'COMP-1',
'address': {'city_name': 'Amsterdam', 'country_code': 'NL'},
},
'lots': [
{'lot_id': 'LOT-1', 'title': 'Lot title', 'description': 'Lot desc'},
],
'official_languages': ['en', 'nl'],
'status': 'active',
};
test('parses notice/form/language, lots and official_languages', () {
final tender = TenderData.fromJson(baseJson(
issueDate: 1700000000,
issueTime: 1700003600,
));
expect(tender.noticeTypeCode, 'NT-1');
expect(tender.formType, 'open');
expect(tender.noticeLanguageCode, 'en');
expect(tender.officialLanguages, ['en', 'nl']);
expect(tender.lots, hasLength(1));
expect(tender.lots?.first.lotId, 'LOT-1');
expect(tender.buyerOrganization?.address?.cityName, 'Amsterdam');
});
test('issue_date/issue_time accept epoch seconds', () {
final tender = TenderData.fromJson(baseJson(
issueDate: 1700000000,
issueTime: 1700003600,
));
expect(tender.issueDate, 1700000000);
expect(tender.issueTime, 1700003600);
});
test('issue_date/issue_time accept millisecond and string inputs', () {
final tender = TenderData.fromJson(baseJson(
issueDate: '1700000000',
issueTime: 1700000000000,
));
// unixTimestampFromJson normalizes the raw value; the >1e10 ms value is
// kept as-is here (timeConvertor downscales it at display time).
expect(tender.issueDate, 1700000000);
expect(tender.issueTime, 1700000000000);
});
test('non-positive or missing issue_date/issue_time become null', () {
final tender = TenderData.fromJson(baseJson(
issueDate: 0,
issueTime: null,
));
expect(tender.issueDate, isNull);
expect(tender.issueTime, isNull);
});
});
}