Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// SPDX-License-Identifier: GPL-3.0-or-later
package dev.itsvic.parceltracker.api

import android.content.Context
import android.os.LocaleList
import com.squareup.moshi.JsonClass
import dev.itsvic.parceltracker.R
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import retrofit2.HttpException
import retrofit2.Retrofit
import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.Query

object ColissimoDeliveryService : DeliveryService {
override val nameResource: Int = R.string.service_colissimo
override val acceptsPostCode: Boolean = false
override val requiresPostCode: Boolean = false
override val requiresApiKey: Boolean = false

override fun acceptsFormat(trackingId: String): Boolean {
val parcelFormat = """^[A-Za-z0-9]{11,15}$""".toRegex()
return parcelFormat.accepts(trackingId)
}

override suspend fun getParcel(
context: Context,
trackingId: String,
postalCode: String?
): Parcel {
val locale = LocaleList.getDefault().get(0)

val resp =
try {
service.getShipments(trackingId, locale.language)
} catch (_: HttpException) {
try {
service.getShipments(trackingId, "en") // Retry once with fallback to english
} catch (_: HttpException) {
throw ParcelNonExistentException()
}
}

if (resp.isEmpty()) throw ParcelNonExistentException()
val shipment = resp[0].shipment

var status = Status.Unknown
val events = shipment.event.sortedByDescending { it.order }

if (events.isNotEmpty()) {
val lastEvent = events.first()
status =
when (lastEvent.code) {
"DR1" -> Status.Preadvice // Delivery declaration received
"DR2" -> Status.DeliveryFailure // Issue during preparation
"PC1" -> Status.InWarehouse // Handled
"PC2" -> Status.InWarehouse // Handled in the expediting country
"ET1" -> Status.InTransit // Processing
"ET2" -> Status.InTransit // Processing in the expediting country
"ET3" -> Status.InTransit // Processing in the destination country
"ET4" -> Status.InTransit // Processing in a transit country
"DO1" -> Status.Customs // Entered customs
"DO2" -> Status.Customs // Out of customs
"DO3" -> Status.Customs // Held in customs
"MD2" -> Status.OutForDelivery // Distributing
"ND1" -> Status.DeliveryFailure // Impossible to distribute
"AG1" -> Status.AwaitingPickup // Awaiting pickup at counter
"RE1" -> Status.DeliveryFailure // Returned to the expeditor
"DI0" -> Status.Delivered // Distributed in lot
"DI1" -> Status.Delivered // Distributed
"DI2" -> Status.DeliveryFailure // Distributed to the expeditor (If sent back I suppose)
"DI3" -> Status.OutForDelivery // Delayed (This probably means still distributing)
"ID0" -> Status.Customs // Customs information
// EP1 (Waiting presentation), PB1 (Issue in progress), PB2 (Issue resolved)
// Ignored as unknown statuses, these errors are mid process statuses so
// it shouldn't be a big deal
else -> logUnknownStatus("Colissimo", lastEvent.code)
}
}

val history =
events.map {
ParcelHistoryItem(
it.label, LocalDateTime.parse(it.date, DateTimeFormatter.ISO_DATE_TIME), it.country)
}

return Parcel(shipment.idShip, history, status)
}

private val retrofit =
Retrofit.Builder()
.baseUrl("https://www.laposte.fr/ssu/sun/back/suivi-unifie/")
.client(api_client)
.addConverterFactory(api_factory)
.build()
private val service = retrofit.create(API::class.java)

private interface API {
@GET("{id}")
suspend fun getShipments(
@Path("id") trackingId: String,
@Query("lang") lang: String = "en_GB"
): List<ShipmentResponse>
}

@JsonClass(generateAdapter = true)
internal data class ShipmentResponse(
val shipment: Shipment,
)

@JsonClass(generateAdapter = true)
internal data class Shipment(
val idShip: String,
val event: List<Event>,
)

@JsonClass(generateAdapter = true)
internal data class Event(
val code: String,
val type: String,
val group: String,
val label: String,
val date: String,
val country: String,
val order: Int
)
}
2 changes: 2 additions & 0 deletions app/src/main/java/dev/itsvic/parceltracker/api/Core.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ enum class Service {
SAMEDAY_RO,
UKRPOSHTA,
POSTNORD,
COLISSIMO,

// Asia
EKART,
Expand Down Expand Up @@ -87,6 +88,7 @@ fun getDeliveryService(service: Service): DeliveryService? {
Service.SAMEDAY_RO -> SamedayRomaniaDeliveryService
Service.UKRPOSHTA -> UkrposhtaDeliveryService
Service.POSTNORD -> PostNordDeliveryService
Service.COLISSIMO -> ColissimoDeliveryService

Service.EKART -> EKartDeliveryService
Service.SPX_TH -> SPXThailandDeliveryService
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<string name="service_an_post" translatable="false">An Post</string>
<string name="service_belpost">Belpost</string>
<string name="service_cainiao" translatable="false">Cainiao</string>
<string name="service_colissimo" translatable="false">Colissimo</string>
<string name="service_dhl" translatable="false">DHL</string>
<string name="service_dpd_ger">DPD Germany</string>
<string name="service_dpd_uk">DPD UK</string>
Expand Down