Files
Verde-Web/app/Models/CollectionLog.php
admin 8643057c81 feat(backend): complete Module 11 (scanning + collection logs)
collection_logs table. ScanService validates code state (active only;
used = duplicate, expired = expired, unassigned/allocated = invalid),
geo proximity (≤200m from DOP via ST_Distance_Sphere), then atomically
transitions code -> Used and writes a CollectionLog. Scans inside a
trip context bump trip_stop.total_scans + emit qr_scanned timeline event.
Bulk scan endpoint processes each scan independently for offline sync.
Triggers QrBalanceLow when household active count drops below threshold.

155 feature tests passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 02:53:25 +08:00

62 lines
1.5 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use MatanYadaev\EloquentSpatial\Objects\Point;
use MatanYadaev\EloquentSpatial\Traits\HasSpatial;
class CollectionLog extends Model
{
use HasFactory, HasSpatial;
public const STATUS_VALID = 'valid';
public const STATUS_INVALID = 'invalid';
public const STATUS_DUPLICATE = 'duplicate';
public const STATUS_EXPIRED = 'expired';
protected $fillable = [
'qr_code_id', 'household_id', 'drop_off_point_id',
'scanned_by_user_id', 'trip_id', 'trip_stop_id',
'scanned_at', 'coordinates_at_scan',
'weight_kg', 'waste_type', 'photo_path', 'notes',
'verification_status',
];
protected function casts(): array
{
return [
'scanned_at' => 'datetime',
'coordinates_at_scan' => Point::class,
'weight_kg' => 'integer',
];
}
public function qrCode(): BelongsTo
{
return $this->belongsTo(QrCode::class);
}
public function household(): BelongsTo
{
return $this->belongsTo(Household::class);
}
public function dropOffPoint(): BelongsTo
{
return $this->belongsTo(DropOffPoint::class);
}
public function scannedBy(): BelongsTo
{
return $this->belongsTo(User::class, 'scanned_by_user_id');
}
public function trip(): BelongsTo
{
return $this->belongsTo(Trip::class);
}
}