158 lines
5.3 KiB
Dart
158 lines
5.3 KiB
Dart
import 'dart:async';
|
||
import 'package:pocketbase/pocketbase.dart';
|
||
import '../../../core/api/pocketbase_client.dart';
|
||
import '../../../core/services/finance_service.dart';
|
||
import '../../../core/services/job_history_service.dart';
|
||
import '../../../models/job.dart';
|
||
|
||
const _listExpand = 'clinic_tenant_id,lab_tenant_id,patient_id';
|
||
const _detailExpand = 'clinic_tenant_id,lab_tenant_id,patient_id,prosthetic_id';
|
||
|
||
class LabJobsRepository {
|
||
LabJobsRepository._();
|
||
static final instance = LabJobsRepository._();
|
||
|
||
PocketBase get _pb => PocketBaseClient.instance.pb;
|
||
|
||
Future<List<Job>> listInbound(
|
||
String labTenantId, {
|
||
String? status,
|
||
int page = 1,
|
||
int limit = 30,
|
||
}) async {
|
||
final filterParts = ['lab_tenant_id = "$labTenantId"'];
|
||
if (status != null) filterParts.add('status = "$status"');
|
||
|
||
final result = await _pb.collection('jobs').getList(
|
||
page: page,
|
||
perPage: limit,
|
||
filter: filterParts.join(' && '),
|
||
expand: _listExpand,
|
||
);
|
||
return (result.items.map((r) => Job.fromJson(r.toJson())).toList()
|
||
..sort((a, b) => b.dateCreated.compareTo(a.dateCreated)));
|
||
}
|
||
|
||
Future<List<Job>> listInProgress(String labTenantId,
|
||
{int limit = 50, String? location}) async {
|
||
final filterParts = [
|
||
'lab_tenant_id = "$labTenantId"',
|
||
'status = "in_progress"'
|
||
];
|
||
if (location != null) filterParts.add('location = "$location"');
|
||
final result = await _pb.collection('jobs').getList(
|
||
perPage: limit,
|
||
filter: filterParts.join(' && '),
|
||
expand: _listExpand,
|
||
);
|
||
return (result.items.map((r) => Job.fromJson(r.toJson())).toList()
|
||
..sort((a, b) {
|
||
if (a.dueDate == null && b.dueDate == null) {
|
||
return b.dateCreated.compareTo(a.dateCreated);
|
||
}
|
||
if (a.dueDate == null) return 1;
|
||
if (b.dueDate == null) return -1;
|
||
final cmp = a.dueDate!.compareTo(b.dueDate!);
|
||
return cmp != 0 ? cmp : b.dateCreated.compareTo(a.dateCreated);
|
||
}));
|
||
}
|
||
|
||
Future<Job> getJob(String jobId) async {
|
||
final record =
|
||
await _pb.collection('jobs').getOne(jobId, expand: _detailExpand);
|
||
return Job.fromJson(record.toJson());
|
||
}
|
||
|
||
Future<Job> acceptJob(Job pendingJob) async {
|
||
final firstStep = pendingJob.stepTemplate.first;
|
||
final record = await _pb.collection('jobs').update(pendingJob.id, body: {
|
||
'status': 'in_progress',
|
||
'current_step': firstStep.value,
|
||
'location': 'at_lab',
|
||
});
|
||
final job = Job.fromJson(record.toJson());
|
||
unawaited(JobHistoryService.instance.append(
|
||
jobId: pendingJob.id,
|
||
clinicTenantId: job.clinicTenantId,
|
||
labTenantId: job.labTenantId,
|
||
action: JobHistoryAction.accepted,
|
||
step: firstStep,
|
||
));
|
||
return job;
|
||
}
|
||
|
||
Future<Job> handToClinic(String jobId, Job job, {String? note}) async {
|
||
final currentStep = job.currentStep;
|
||
if (currentStep == null) {
|
||
throw Exception('Geçerli bir iş adımı bulunamadı.');
|
||
}
|
||
|
||
final isFinal = currentStep == JobStep.cilaBitim;
|
||
final nextStep = job.nextStep;
|
||
final patch = isFinal
|
||
? {'status': 'sent', 'location': 'at_clinic'}
|
||
: currentStep.requiresClinicApproval
|
||
? {'location': 'at_clinic'}
|
||
: {
|
||
'current_step': nextStep?.value,
|
||
'location': 'at_lab',
|
||
};
|
||
|
||
final record = await _pb.collection('jobs').update(jobId, body: patch);
|
||
final updated = Job.fromJson(record.toJson());
|
||
unawaited(JobHistoryService.instance.append(
|
||
jobId: jobId,
|
||
clinicTenantId: job.clinicTenantId,
|
||
labTenantId: job.labTenantId,
|
||
action: currentStep.requiresClinicApproval || isFinal
|
||
? JobHistoryAction.handedToClinic
|
||
: JobHistoryAction.stepCompleted,
|
||
step: currentStep,
|
||
note: note,
|
||
));
|
||
return updated;
|
||
}
|
||
|
||
Future<Job> cancelJob(String jobId, Job job) async {
|
||
final record = await _pb.collection('jobs').update(jobId, body: {
|
||
'status': 'cancelled',
|
||
});
|
||
await FinanceService.instance.deletePendingEntriesForJob(jobId);
|
||
unawaited(JobHistoryService.instance.append(
|
||
jobId: jobId,
|
||
clinicTenantId: job.clinicTenantId,
|
||
labTenantId: job.labTenantId,
|
||
action: JobHistoryAction.cancelled,
|
||
step: job.currentStep,
|
||
));
|
||
return Job.fromJson(record.toJson());
|
||
}
|
||
|
||
Future<void> bulkAcceptPending(String labTenantId) async {
|
||
final pending =
|
||
await listInbound(labTenantId, status: 'pending', limit: 200);
|
||
await Future.wait(pending.map((j) => acceptJob(j)));
|
||
}
|
||
|
||
Future<int> countByStatus(String labTenantId, String? status) async {
|
||
final filter = status != null
|
||
? 'lab_tenant_id = "$labTenantId" && status = "$status"'
|
||
: 'lab_tenant_id = "$labTenantId"';
|
||
final r = await _pb.collection('jobs').getList(perPage: 1, filter: filter);
|
||
return r.totalItems;
|
||
}
|
||
|
||
Future<int> countDelivered(String labTenantId,
|
||
{DateTime? from, DateTime? to}) async {
|
||
final parts = ['lab_tenant_id = "$labTenantId"', 'status = "delivered"'];
|
||
if (from != null) parts.add('updated >= "${_date(from)}"');
|
||
if (to != null) parts.add('updated < "${_date(to)}"');
|
||
final r = await _pb
|
||
.collection('jobs')
|
||
.getList(perPage: 1, filter: parts.join(' && '));
|
||
return r.totalItems;
|
||
}
|
||
|
||
static String _date(DateTime d) => d.toIso8601String().split('T').first;
|
||
}
|