Files
lab-app/lib/features/lab/jobs/lab_jobs_repository.dart
T
2026-10-10 14:52:05 +03:00

159 lines
5.4 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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,
sort: '-created',
);
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,
sort: location == null ? '-created' : null,
);
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,
{required bool finish, required String note}) async {
if (note.trim().isEmpty) {
throw ArgumentError('Aşama açıklaması gereklidir.');
}
final dispatchStep = job.labDispatchStep(finish: finish);
final steps = [...job.stepTemplate];
if (!steps.contains(dispatchStep)) {
steps.insert(0, dispatchStep);
}
final patch = {
'status': finish ? 'sent' : 'in_progress',
'location': 'at_clinic',
'current_step': dispatchStep.value,
'workflow_steps': steps.map((step) => step.value).toList(),
};
final record = await _pb.collection('jobs').update(jobId, body: patch);
final updated = Job.fromJson(record.toJson());
await JobHistoryService.instance.append(
jobId: jobId,
clinicTenantId: job.clinicTenantId,
labTenantId: job.labTenantId,
action: JobHistoryAction.handedToClinic,
step: dispatchStep,
note:
'${finish ? "Bitime gönderildi" : "Provaya gönderildi"}: ${note.trim()}',
);
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;
}