Dto Structres Created:
/// <summary>
/// Family module insurance from GET /familymodules/{PatNum}/Insurance.
/// Combines PatPlan + InsSub + Carrier + Plan level info in one response.
/// </summary>
public List<OpenDentalFamilyInsuranceDto> FamilyInsurances { get; set; } = new();
/// <summary>
/// Payment splits from GET /paysplits.
/// Represents how payments are allocated (to procedures, plans, etc.).
/// </summary>
public List<OpenDentalPaySplitDto> PaySplits { get; set; } = new();
using System;
using System.Text.Json.Serialization;
using DentpalApiService.Dtos.Conversions;
using JsonConverter = Newtonsoft.Json.JsonConverter;
using JsonConverterAttribute = Newtonsoft.Json.JsonConverterAttribute;
namespace DentPal.Patients.PMS.OpenDental.Dtos;
///
/// DTO representing a payment split in OpenDental.
/// Matches the JSON schema returned by the OpenDental API.
///
[JsonConverter(typeof(OpenDentalPaySplitConverter))]
public class OpenDentalPaySplitDto
{
///
/// Split number (primary key).
///
[JsonPropertyName("SplitNum")]
public int SplitNum { get; set; }
/// <summary>
/// Split amount.
/// </summary>
[JsonPropertyName("SplitAmt")]
public decimal SplitAmt { get; set; }
/// <summary>
/// Patient number.
/// </summary>
[JsonPropertyName("PatNum")]
public int PatNum { get; set; }
/// <summary>
/// Payment number.
/// </summary>
[JsonPropertyName("PayNum")]
public int PayNum { get; set; }
/// <summary>
/// Provider number.
/// </summary>
[JsonPropertyName("ProvNum")]
public int ProvNum { get; set; }
/// <summary>
/// Payment plan number.
/// </summary>
[JsonPropertyName("PayPlanNum")]
public int PayPlanNum { get; set; }
/// <summary>
/// Payment date.
/// </summary>
[JsonPropertyName("DatePay")]
public DateTime DatePay { get; set; }
/// <summary>
/// Procedure number.
/// </summary>
[JsonPropertyName("ProcNum")]
public int ProcNum { get; set; }
/// <summary>
/// Entry date.
/// </summary>
[JsonPropertyName("DateEntry")]
public DateTime DateEntry { get; set; }
/// <summary>
/// Unearned type (numeric).
/// </summary>
[JsonPropertyName("UnearnedType")]
public int UnearnedType { get; set; }
/// <summary>
/// Unearned type name (text).
/// </summary>
[JsonPropertyName("unearnedType")]
public string UnearnedTypeName { get; set; }
/// <summary>
/// Clinic number.
/// </summary>
[JsonPropertyName("ClinicNum")]
public int ClinicNum { get; set; }
/// <summary>
/// Last edit timestamp.
/// </summary>
[JsonPropertyName("SecDateTEdit")]
public DateTime SecDateTEdit { get; set; }
/// <summary>
/// Adjustment number.
/// </summary>
[JsonPropertyName("AdjNum")]
public int AdjNum { get; set; }
/// <summary>
/// Payment plan charge number.
/// </summary>
[JsonPropertyName("PayPlanChargeNum")]
public int PayPlanChargeNum { get; set; }
/// <summary>
/// Payment plan debit type.
/// </summary>
[JsonPropertyName("PayPlanDebitType")]
public string PayPlanDebitType { get; set; }
}
using System.Text.Json.Serialization;
using DentpalApiService.Dtos.Conversions;
using JsonConverter = Newtonsoft.Json.JsonConverter;
using JsonConverterAttribute = Newtonsoft.Json.JsonConverterAttribute;
namespace DentPal.Patients.PMS.OpenDental.Dtos;
///
/// DTO representing Family Module Insurance from OpenDental.
/// Matches the JSON schema returned by the OpenDental API.
///
[JsonConverter(typeof(OpenDentalFamilyInsuranceConverter))]
public class OpenDentalFamilyInsuranceDto
{
[JsonPropertyName("PatNum")]
public int PatNum { get; set; }
[JsonPropertyName("InsSubNum")]
public int InsSubNum { get; set; }
[JsonPropertyName("Subscriber")]
public int Subscriber { get; set; }
[JsonPropertyName("subscriber")]
public string SubscriberName { get; set; }
[JsonPropertyName("SubscriberID")]
public string SubscriberID { get; set; }
[JsonPropertyName("SubscNote")]
public string SubscNote { get; set; }
[JsonPropertyName("PatPlanNum")]
public int PatPlanNum { get; set; }
[JsonPropertyName("Ordinal")]
public int Ordinal { get; set; }
[JsonPropertyName("ordinal")]
public string OrdinalName { get; set; }
[JsonPropertyName("IsPending")]
public string IsPending { get; set; }
[JsonPropertyName("Relationship")]
public string Relationship { get; set; }
[JsonPropertyName("PatID")]
public string PatID { get; set; }
[JsonPropertyName("CarrierNum")]
public int CarrierNum { get; set; }
[JsonPropertyName("CarrierName")]
public string CarrierName { get; set; }
[JsonPropertyName("PlanNum")]
public int PlanNum { get; set; }
[JsonPropertyName("GroupName")]
public string GroupName { get; set; }
[JsonPropertyName("GroupNum")]
public string GroupNum { get; set; }
[JsonPropertyName("PlanNote")]
public string PlanNote { get; set; }
[JsonPropertyName("FeeSched")]
public int FeeSched { get; set; }
[JsonPropertyName("feeSchedule")]
public string FeeScheduleName { get; set; }
[JsonPropertyName("PlanType")]
public string PlanType { get; set; }
[JsonPropertyName("planType")]
public string PlanTypeName { get; set; }
[JsonPropertyName("CopayFeeSched")]
public int CopayFeeSched { get; set; }
[JsonPropertyName("EmployerNum")]
public int EmployerNum { get; set; }
[JsonPropertyName("employer")]
public string EmployerName { get; set; }
[JsonPropertyName("IsMedical")]
public string IsMedical { get; set; }
}
Converters:¶
using DentPal.Patients.PMS.OpenDental.Dtos;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
namespace DentpalApiService.Dtos.Conversions
{
public class OpenDentalFamilyInsuranceConverter
: JsonConverter
{
public override OpenDentalFamilyInsuranceDto ReadJson(
JsonReader reader,
Type objectType,
OpenDentalFamilyInsuranceDto existingValue,
bool hasExistingValue,
JsonSerializer serializer)
{
var obj = JObject.Load(reader);
var dto = new OpenDentalFamilyInsuranceDto();
// ---- Ordinal (numeric) ----
if (obj.TryGetValue("Ordinal", StringComparison.Ordinal, out var ordinalNum) &&
ordinalNum.Type == JTokenType.Integer)
{
dto.Ordinal = ordinalNum.Value<int>();
}
// ---- ordinal (text) ----
if (obj.TryGetValue("ordinal", StringComparison.Ordinal, out var ordinalText) &&
ordinalText.Type == JTokenType.String)
{
dto.OrdinalName = ordinalText.Value<string>();
}
// ---- FeeSched / feeSchedule ----
if (obj.TryGetValue("FeeSched", StringComparison.Ordinal, out var feeNum) &&
feeNum.Type == JTokenType.Integer)
{
dto.FeeSched = feeNum.Value<int>();
}
if (obj.TryGetValue("feeSchedule", StringComparison.Ordinal, out var feeText) &&
feeText.Type == JTokenType.String)
{
dto.FeeScheduleName = feeText.Value<string>();
}
// ---- PlanType / planType ----
if (obj.TryGetValue("PlanType", StringComparison.Ordinal, out var planType) &&
planType.Type == JTokenType.String)
{
dto.PlanType = planType.Value<string>();
}
if (obj.TryGetValue("planType", StringComparison.Ordinal, out var planTypeText) &&
planTypeText.Type == JTokenType.String)
{
dto.PlanTypeName = planTypeText.Value<string>();
}
// Remove duplicates to avoid collision
obj.Remove("Ordinal");
obj.Remove("ordinal");
obj.Remove("FeeSched");
obj.Remove("feeSchedule");
obj.Remove("PlanType");
obj.Remove("planType");
serializer.Populate(obj.CreateReader(), dto);
return dto;
}
public override void WriteJson(
JsonWriter writer,
OpenDentalFamilyInsuranceDto value,
JsonSerializer serializer)
{
writer.WriteStartObject();
// Ordinal
writer.WritePropertyName("Ordinal");
writer.WriteValue(value.Ordinal);
if (!string.IsNullOrEmpty(value.OrdinalName))
{
writer.WritePropertyName("ordinal");
writer.WriteValue(value.OrdinalName);
}
// FeeSched
writer.WritePropertyName("FeeSched");
writer.WriteValue(value.FeeSched);
if (!string.IsNullOrEmpty(value.FeeScheduleName))
{
writer.WritePropertyName("feeSchedule");
writer.WriteValue(value.FeeScheduleName);
}
// PlanType
if (!string.IsNullOrEmpty(value.PlanType))
{
writer.WritePropertyName("PlanType");
writer.WriteValue(value.PlanType);
}
if (!string.IsNullOrEmpty(value.PlanTypeName))
{
writer.WritePropertyName("planType");
writer.WriteValue(value.PlanTypeName);
}
serializer.Serialize(writer, value);
writer.WriteEndObject();
}
}
}
using DentPal.Patients.PMS.OpenDental.Dtos;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
namespace DentpalApiService.Dtos.Conversions
{
public class OpenDentalPaySplitConverter
: JsonConverter
{
public override OpenDentalPaySplitDto ReadJson(
JsonReader reader,
Type objectType,
OpenDentalPaySplitDto existingValue,
bool hasExistingValue,
JsonSerializer serializer)
{
var obj = JObject.Load(reader);
var dto = new OpenDentalPaySplitDto();
// ---- UnearnedType (numeric) ----
if (obj.TryGetValue("UnearnedType", StringComparison.Ordinal, out var typeNum) &&
typeNum.Type == JTokenType.Integer)
{
dto.UnearnedType = typeNum.Value<int>();
}
// ---- unearnedType (text) ----
if (obj.TryGetValue("unearnedType", StringComparison.Ordinal, out var typeText) &&
typeText.Type == JTokenType.String)
{
dto.UnearnedTypeName = typeText.Value<string>();
}
// Remove both to avoid collision
obj.Remove("UnearnedType");
obj.Remove("unearnedType");
// Populate remaining properties
serializer.Populate(obj.CreateReader(), dto);
return dto;
}
public override void WriteJson(
JsonWriter writer,
OpenDentalPaySplitDto value,
JsonSerializer serializer)
{
writer.WriteStartObject();
writer.WritePropertyName("UnearnedType");
writer.WriteValue(value.UnearnedType);
if (!string.IsNullOrEmpty(value.UnearnedTypeName))
{
writer.WritePropertyName("unearnedType");
writer.WriteValue(value.UnearnedTypeName);
}
serializer.Serialize(writer, value);
writer.WriteEndObject();
}
}
}