Returning now all mails and attachments, not only those with eInvoices
This commit is contained in:
parent
c3cf0652b2
commit
d70a748ad0
|
@ -32,7 +32,7 @@ val fetchResult = emailsFetcher.fetchAllEmails(EmailAccount(
|
||||||
))
|
))
|
||||||
|
|
||||||
fetchResult.emails.forEach { email ->
|
fetchResult.emails.forEach { email ->
|
||||||
println("${email.sender}: ${email.attachmentsWithEInvoice.firstNotNullOfOrNull { it.invoice }?.totalAmounts?.duePayableAmount}")
|
println("${email.sender}: ${email.attachments.firstNotNullOfOrNull { it.invoice }?.totalAmounts?.duePayableAmount}")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ import jakarta.mail.event.MessageCountAdapter
|
||||||
import jakarta.mail.event.MessageCountEvent
|
import jakarta.mail.event.MessageCountEvent
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.codinux.invoicing.email.model.EmailAccount
|
import net.codinux.invoicing.email.model.EmailAccount
|
||||||
import net.codinux.invoicing.email.model.EmailAttachmentWithEInvoice
|
import net.codinux.invoicing.email.model.EmailAttachment
|
||||||
import net.codinux.invoicing.email.model.EmailWithInvoice
|
import net.codinux.invoicing.email.model.Email
|
||||||
import net.codinux.invoicing.model.Invoice
|
import net.codinux.invoicing.model.Invoice
|
||||||
import net.codinux.invoicing.reader.EInvoiceReader
|
import net.codinux.invoicing.reader.EInvoiceReader
|
||||||
import net.codinux.log.logger
|
import net.codinux.log.logger
|
||||||
|
@ -47,7 +47,7 @@ open class EmailsFetcher(
|
||||||
folder.addMessageCountListener(object : MessageCountAdapter() {
|
folder.addMessageCountListener(object : MessageCountAdapter() {
|
||||||
override fun messagesAdded(event: MessageCountEvent) {
|
override fun messagesAdded(event: MessageCountEvent) {
|
||||||
event.messages.forEach { message ->
|
event.messages.forEach { message ->
|
||||||
findEInvoice(message, status)
|
getEmail(message, status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -102,7 +102,7 @@ open class EmailsFetcher(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun fetchAllEmailsInFolder(folder: Folder, status: FetchEmailsStatus): List<EmailWithInvoice> = runBlocking {
|
protected open fun fetchAllEmailsInFolder(folder: Folder, status: FetchEmailsStatus): List<Email> = runBlocking {
|
||||||
val messageCount = folder.messageCount
|
val messageCount = folder.messageCount
|
||||||
if (messageCount <= 0) {
|
if (messageCount <= 0) {
|
||||||
return@runBlocking emptyList()
|
return@runBlocking emptyList()
|
||||||
|
@ -111,7 +111,7 @@ open class EmailsFetcher(
|
||||||
IntRange(1, messageCount).mapNotNull { messageNumber -> // message numbers start at 1
|
IntRange(1, messageCount).mapNotNull { messageNumber -> // message numbers start at 1
|
||||||
async(coroutineDispatcher) {
|
async(coroutineDispatcher) {
|
||||||
try {
|
try {
|
||||||
findEInvoice(folder.getMessage(messageNumber), status)
|
getEmail(folder.getMessage(messageNumber), status)
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
log.error(e) { "Could not get email with messageNumber $messageNumber" }
|
log.error(e) { "Could not get email with messageNumber $messageNumber" }
|
||||||
status.addError(FetchEmailsErrorType.GetEmail, messageNumber, e)
|
status.addError(FetchEmailsErrorType.GetEmail, messageNumber, e)
|
||||||
|
@ -123,43 +123,39 @@ open class EmailsFetcher(
|
||||||
.filterNotNull()
|
.filterNotNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun findEInvoice(message: Message, status: FetchEmailsStatus): EmailWithInvoice? {
|
protected open fun getEmail(message: Message, status: FetchEmailsStatus): Email? {
|
||||||
val parts = getAllMessageParts(message)
|
val parts = getAllMessageParts(message)
|
||||||
|
|
||||||
val attachmentsWithEInvoice = parts.mapNotNull { part ->
|
val attachments = parts.mapNotNull { part ->
|
||||||
findEInvoice(part, status)
|
findAttachment(part, status)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attachmentsWithEInvoice.isNotEmpty()) {
|
val email = Email(
|
||||||
val email = EmailWithInvoice(
|
message.from?.joinToString(), message.subject ?: "",
|
||||||
message.from?.joinToString(), message.subject ?: "",
|
message.sentDate?.let { map(it) }, map(message.receivedDate), message.messageNumber,
|
||||||
message.sentDate?.let { map(it) }, map(message.receivedDate), message.messageNumber,
|
parts.any { it.mediaType == "application/pgp-encrypted" },
|
||||||
parts.any { it.mediaType == "application/pgp-encrypted" },
|
getPlainTextBody(parts, status), getHtmlBody(parts, status),
|
||||||
getPlainTextBody(parts, status), getHtmlBody(parts, status),
|
attachments
|
||||||
attachmentsWithEInvoice
|
)
|
||||||
)
|
|
||||||
|
|
||||||
status.options.emailReceived(email)
|
status.options.emailReceived(email)
|
||||||
|
|
||||||
return email
|
return email
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun findEInvoice(messagePart: MessagePart, status: FetchEmailsStatus): EmailAttachmentWithEInvoice? {
|
protected open fun findAttachment(messagePart: MessagePart, status: FetchEmailsStatus): EmailAttachment? {
|
||||||
try {
|
try {
|
||||||
val part = messagePart.part
|
val part = messagePart.part
|
||||||
val invoice = tryToReadEInvoice(part, messagePart.mediaType, status)
|
val invoice = tryToReadEInvoice(part, messagePart.mediaType, status)
|
||||||
|
|
||||||
if (invoice != null) {
|
if (invoice != null || Part.ATTACHMENT.equals(part.description, ignoreCase = true)) {
|
||||||
val filename = File(part.fileName)
|
val filename = File(part.fileName)
|
||||||
val file = File.createTempFile(filename.nameWithoutExtension, "." + filename.extension).also { file ->
|
val file = File.createTempFile(filename.nameWithoutExtension, "." + filename.extension).also { file ->
|
||||||
part.inputStream.use { it.copyTo(file.outputStream()) }
|
part.inputStream.use { it.copyTo(file.outputStream()) }
|
||||||
file.deleteOnExit()
|
file.deleteOnExit()
|
||||||
}
|
}
|
||||||
|
|
||||||
return EmailAttachmentWithEInvoice(part.fileName, messagePart.mediaType, invoice, file)
|
return EmailAttachment(part.fileName, messagePart.mediaType, invoice, file)
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
log.error(e) { "Could not check attachment '${messagePart.part.fileName}' (${messagePart.mediaType}) for eInvoice" }
|
log.error(e) { "Could not check attachment '${messagePart.part.fileName}' (${messagePart.mediaType}) for eInvoice" }
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
package net.codinux.invoicing.email
|
package net.codinux.invoicing.email
|
||||||
|
|
||||||
import net.codinux.invoicing.email.model.EmailWithInvoice
|
import net.codinux.invoicing.email.model.Email
|
||||||
|
|
||||||
open class FetchEmailsOptions(
|
open class FetchEmailsOptions(
|
||||||
val downloadMessageBody: Boolean = false,
|
val downloadMessageBody: Boolean = false,
|
||||||
val emailFolderName: String = "INBOX",
|
val emailFolderName: String = "INBOX",
|
||||||
|
|
||||||
val onError: ((FetchEmailsError) -> Unit)? = null,
|
val onError: ((FetchEmailsError) -> Unit)? = null,
|
||||||
val onEmailReceived: ((EmailWithInvoice) -> Unit)? = null
|
val onEmailReceived: ((Email) -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
fun emailReceived(email: EmailWithInvoice) {
|
fun emailReceived(email: Email) {
|
||||||
onEmailReceived?.invoke(email)
|
onEmailReceived?.invoke(email)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
package net.codinux.invoicing.email
|
package net.codinux.invoicing.email
|
||||||
|
|
||||||
import net.codinux.invoicing.email.model.EmailWithInvoice
|
import net.codinux.invoicing.email.model.Email
|
||||||
|
|
||||||
data class FetchEmailsResult(
|
data class FetchEmailsResult(
|
||||||
val emails: List<EmailWithInvoice>,
|
val emails: List<Email>,
|
||||||
val overallError: Throwable?,
|
val overallError: Throwable?,
|
||||||
val messageSpecificErrors: List<FetchEmailsError> = emptyList()
|
val messageSpecificErrors: List<FetchEmailsError> = emptyList()
|
||||||
)
|
)
|
|
@ -1,6 +1,6 @@
|
||||||
package net.codinux.invoicing.email
|
package net.codinux.invoicing.email
|
||||||
|
|
||||||
import net.codinux.invoicing.email.model.EmailWithInvoice
|
import net.codinux.invoicing.email.model.Email
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
open class ListenForNewMailsOptions(
|
open class ListenForNewMailsOptions(
|
||||||
|
@ -10,5 +10,5 @@ open class ListenForNewMailsOptions(
|
||||||
emailFolderName: String = "INBOX",
|
emailFolderName: String = "INBOX",
|
||||||
|
|
||||||
onError: ((FetchEmailsError) -> Unit)? = null,
|
onError: ((FetchEmailsError) -> Unit)? = null,
|
||||||
onEmailReceived: (EmailWithInvoice) -> Unit
|
onEmailReceived: (Email) -> Unit
|
||||||
) : FetchEmailsOptions(downloadMessageBody, emailFolderName, onError, onEmailReceived)
|
) : FetchEmailsOptions(downloadMessageBody, emailFolderName, onError, onEmailReceived)
|
|
@ -3,7 +3,7 @@ package net.codinux.invoicing.email.model
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
|
|
||||||
class EmailWithInvoice(
|
class Email(
|
||||||
val sender: String?,
|
val sender: String?,
|
||||||
val subject: String,
|
val subject: String,
|
||||||
val sent: Instant?,
|
val sent: Instant?,
|
||||||
|
@ -19,9 +19,9 @@ class EmailWithInvoice(
|
||||||
val isEncrypted: Boolean = false,
|
val isEncrypted: Boolean = false,
|
||||||
val plainTextBody: String?,
|
val plainTextBody: String?,
|
||||||
val htmlBody: String?,
|
val htmlBody: String?,
|
||||||
val attachmentsWithEInvoice: List<EmailAttachmentWithEInvoice>
|
val attachments: List<EmailAttachment>
|
||||||
) {
|
) {
|
||||||
val plainTextOrHtmlBody: String? by lazy { plainTextBody ?: htmlBody }
|
val plainTextOrHtmlBody: String? by lazy { plainTextBody ?: htmlBody }
|
||||||
|
|
||||||
override fun toString() = "${(sent ?: received).atZone(ZoneId.systemDefault()).toLocalDate()} $sender: $subject, ${attachmentsWithEInvoice.size} invoice(s)"
|
override fun toString() = "${(sent ?: received).atZone(ZoneId.systemDefault()).toLocalDate()} $sender: $subject, ${attachments.size} attachment(s)"
|
||||||
}
|
}
|
|
@ -3,7 +3,7 @@ package net.codinux.invoicing.email.model
|
||||||
import net.codinux.invoicing.model.Invoice
|
import net.codinux.invoicing.model.Invoice
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class EmailAttachmentWithEInvoice(
|
class EmailAttachment(
|
||||||
val filename: String,
|
val filename: String,
|
||||||
/**
|
/**
|
||||||
* Attachment's media type like "application/xml", "application/pdf", ...
|
* Attachment's media type like "application/xml", "application/pdf", ...
|
||||||
|
@ -11,7 +11,7 @@ class EmailAttachmentWithEInvoice(
|
||||||
* Should always be non-null, but can theoretically be null.
|
* Should always be non-null, but can theoretically be null.
|
||||||
*/
|
*/
|
||||||
val mediaType: String?,
|
val mediaType: String?,
|
||||||
val invoice: Invoice,
|
val invoice: Invoice?,
|
||||||
val file: File
|
val file: File
|
||||||
) {
|
) {
|
||||||
override fun toString() = "$filename: $invoice"
|
override fun toString() = "$filename: $invoice"
|
|
@ -35,7 +35,7 @@ class Demonstration {
|
||||||
))
|
))
|
||||||
|
|
||||||
fetchResult.emails.forEach { email ->
|
fetchResult.emails.forEach { email ->
|
||||||
println("${email.sender}: ${email.attachmentsWithEInvoice.firstNotNullOfOrNull { it.invoice }?.totalAmounts?.duePayableAmount}")
|
println("${email.sender}: ${email.attachments.firstNotNullOfOrNull { it.invoice }?.totalAmounts?.duePayableAmount}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue