fix(documents): set publishDate on Document create (Marcus-Law requires it)
The server returned:
400 {"messageTranslation":{"label":"validationFailure",
"data":{"field":"publishDate","type":"required"}}}
Marcus-Law's EspoCRM install marks Document.publishDate as required.
By default the field is optional, but this tenant tightened it. Send
today's date (UTC, YYYY-MM-DD form) so the validation passes — the
user can still edit the published date in EspoCRM later if needed.
Also add the same verbose-error pattern to CreateDocumentAsync that we
already use on UploadAttachmentAsync: when the create returns non-2xx,
log the response body + X-Status-Reason header so any future required-
field mismatch shows up as a single readable line instead of
"שמירת הקבצים נכשלה".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -262,21 +262,47 @@ namespace MarcusLaw.OutlookAddin.Core.Services
|
|||||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("name required", nameof(name));
|
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("name required", nameof(name));
|
||||||
if (string.IsNullOrWhiteSpace(attachmentFileId)) throw new ArgumentException("attachmentFileId required", nameof(attachmentFileId));
|
if (string.IsNullOrWhiteSpace(attachmentFileId)) throw new ArgumentException("attachmentFileId required", nameof(attachmentFileId));
|
||||||
|
|
||||||
|
// Marcus-Law's EspoCRM has `publishDate` configured as required on
|
||||||
|
// Document. The field accepts a plain date (YYYY-MM-DD). Default
|
||||||
|
// to today; the user can edit it later in EspoCRM if needed.
|
||||||
|
var todayIso = DateTimeOffset.UtcNow.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
var payload = new Dictionary<string, object?>
|
var payload = new Dictionary<string, object?>
|
||||||
{
|
{
|
||||||
["name"] = name,
|
["name"] = name,
|
||||||
["fileId"] = attachmentFileId,
|
["fileId"] = attachmentFileId,
|
||||||
["status"] = "Active"
|
["status"] = "Active",
|
||||||
|
["publishDate"] = todayIso
|
||||||
};
|
};
|
||||||
if (!string.IsNullOrWhiteSpace(parentType)) payload["parentType"] = parentType;
|
if (!string.IsNullOrWhiteSpace(parentType)) payload["parentType"] = parentType;
|
||||||
if (!string.IsNullOrWhiteSpace(parentId)) payload["parentId"] = parentId;
|
if (!string.IsNullOrWhiteSpace(parentId)) payload["parentId"] = parentId;
|
||||||
if (!string.IsNullOrWhiteSpace(folderId)) payload["folderId"] = folderId;
|
if (!string.IsNullOrWhiteSpace(folderId)) payload["folderId"] = folderId;
|
||||||
|
|
||||||
var json = JsonSerializer.Serialize(payload, JsonOptions);
|
var json = JsonSerializer.Serialize(payload, JsonOptions);
|
||||||
|
_logger.Information(
|
||||||
|
"CreateDocument POST /Document (name={Name}, fileId={FileId}, parent={ParentType}/{ParentId}, folder={FolderId})",
|
||||||
|
name, attachmentFileId, parentType, parentId, folderId ?? "(none)");
|
||||||
|
|
||||||
var response = await ExecuteAsync(HttpMethod.Post, "Document", json, cancellationToken).ConfigureAwait(false);
|
var response = await ExecuteAsync(HttpMethod.Post, "Document", json, cancellationToken).ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await EnsureSuccessAsync(response).ConfigureAwait(false);
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var errBody = await ReadBodyAsync(response).ConfigureAwait(false);
|
||||||
|
var reason = response.Headers.TryGetValues("X-Status-Reason", out var v)
|
||||||
|
? string.Join(",", v) : "(none)";
|
||||||
|
_logger.Warning(
|
||||||
|
"CreateDocument failed: {Status} (X-Status-Reason={Reason}) body={Body}",
|
||||||
|
response.StatusCode, reason, string.IsNullOrEmpty(errBody) ? "(empty)" : Truncate(errBody, 500));
|
||||||
|
if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden)
|
||||||
|
{
|
||||||
|
throw new EspoCrmAuthorizationException(
|
||||||
|
$"EspoCRM rejected credentials ({(int)response.StatusCode} {response.StatusCode}). Re-enter API key.");
|
||||||
|
}
|
||||||
|
throw new EspoCrmHttpException(response.StatusCode, errBody,
|
||||||
|
$"EspoCRM Document create returned {(int)response.StatusCode} {response.StatusCode}" +
|
||||||
|
(string.IsNullOrEmpty(reason) ? "" : " (reason: " + reason + ")"));
|
||||||
|
}
|
||||||
var body = await ReadBodyAsync(response).ConfigureAwait(false);
|
var body = await ReadBodyAsync(response).ConfigureAwait(false);
|
||||||
return JsonSerializer.Deserialize<DocumentEntity>(body, JsonOptions)
|
return JsonSerializer.Deserialize<DocumentEntity>(body, JsonOptions)
|
||||||
?? throw new EspoCrmHttpException(response.StatusCode, body, "Empty DocumentEntity from EspoCRM");
|
?? throw new EspoCrmHttpException(response.StatusCode, body, "Empty DocumentEntity from EspoCRM");
|
||||||
|
|||||||
Reference in New Issue
Block a user