Feat(Assinatura): Suporte a múltiplas assinaturas digitais em Matéria e Doc Acessório
Permite que múltiplos co-autores assinem o mesmo documento sequencialmente.
O primeiro assinante usa o fluxo atual (ReportLab + pyhanko), e os subsequentes
adicionam assinatura incremental preservando as anteriores. Template mostra
botões "Ver PDF Assinado" e "Assinar" simultaneamente, e o card lista todos
os assinantes. Backward-compatible com assinatura_info legado (dict → lista).
Co-Authored-By: rangelbruno <rangelbruno@users.noreply.github.com>
<iclass="fa fa-certificate"></i> {% trans "Assinar PDF Digitalmente" %}
</button>
@ -33,32 +34,37 @@
<divclass="card border-success">
<divclass="card-header bg-success text-white">
<iclass="fa fa-certificate"></i> {% trans "Assinatura Digital" %}
{% if assinaturas|length > 1 %}
<spanclass="badge badge-light ml-1">{{ assinaturas|length }} {% trans "assinaturas" %}</span>
{% endif %}
</div>
<divclass="card-body">
<divclass="row">
<divclass="col-md-6">
<pclass="mb-1"><strong>{% trans "Status:" %}</strong>
<pclass="mb-2"><strong>{% trans "Status:" %}</strong>
<spanclass="badge badge-success">{% trans "Documento Assinado" %}</span>
</p>
{% if object.assinado_em %}
<pclass="mb-1"><strong>{% trans "Data/Hora:" %}</strong> {{ object.assinado_em|localtime|date:"d/m/Y H:i:s" }}</p>
{% endif %}
{% if object.assinado_por %}
<pclass="mb-1"><strong>{% trans "Assinado por:" %}</strong> {{ object.assinado_por.get_full_name|default:object.assinado_por.username }}</p>
{% endif %}
{% for assinatura in assinaturas %}
<divclass="{% if not forloop.last %}mb-2 pb-2 border-bottom{% endif %}">
<divclass="row">
<divclass="col-md-6">
<pclass="mb-1"><strong>{% trans "Assinado por:" %}</strong> {{ assinatura.nome_assinante }}</p>
<pclass="mb-1"><strong>{% trans "Data/Hora:" %}</strong> {{ assinatura.data_assinatura }}</p>
</div>
<divclass="col-md-6">
{% if object.assinatura_info %}
<pclass="mb-1"><strong>{% trans "Tipo de Certificado:" %}</strong> {{ object.assinatura_info.tipo_certificado|default:"A1" }}</p>
{% if object.assinatura_info.subject %}
<pclass="mb-1"><strong>{% trans "Certificado:" %}</strong> {{ object.assinatura_info.subject|truncatechars:50 }}</p>
{% endif %}
{% if object.assinatura_info.valid_to %}
<pclass="mb-1"><strong>{% trans "Validade:" %}</strong> {{ object.assinatura_info.valid_to|slice:":10" }}</p>
{% endif %}
<pclass="mb-1"><strong>{% trans "Tipo de Certificado:" %}</strong> {{ assinatura.tipo_certificado_display|default:assinatura.tipo_certificado|default:"A1" }}</p>
{% if assinatura.cargo %}
<pclass="mb-1"><strong>{% trans "Cargo:" %}</strong> {{ assinatura.cargo }}</p>
{% endif %}
</div>
</div>
</div>
{% empty %}
{% if object.assinado_por %}
<pclass="mb-1"><strong>{% trans "Assinado por:" %}</strong> {{ object.assinado_por.get_full_name|default:object.assinado_por.username }}</p>
{% endif %}
{% if object.assinado_em %}
<pclass="mb-1"><strong>{% trans "Data/Hora:" %}</strong> {{ object.assinado_em|localtime|date:"d/m/Y H:i:s" }}</p>
<iclass="fa fa-certificate"></i> {% trans "Assinar PDF Digitalmente" %}
</button>
@ -180,32 +181,37 @@
<divclass="card border-success">
<divclass="card-header bg-success text-white">
<iclass="fa fa-certificate"></i> {% trans "Assinatura Digital" %}
{% if assinaturas|length > 1 %}
<spanclass="badge badge-light ml-1">{{ assinaturas|length }} {% trans "assinaturas" %}</span>
{% endif %}
</div>
<divclass="card-body">
<divclass="row">
<divclass="col-md-6">
<pclass="mb-1"><strong>{% trans "Status:" %}</strong>
<pclass="mb-2"><strong>{% trans "Status:" %}</strong>
<spanclass="badge badge-success">{% trans "Documento Assinado" %}</span>
</p>
{% if object.assinado_em %}
<pclass="mb-1"><strong>{% trans "Data/Hora:" %}</strong> {{ object.assinado_em|localtime|date:"d/m/Y H:i:s" }}</p>
{% endif %}
{% if object.assinado_por %}
<pclass="mb-1"><strong>{% trans "Assinado por:" %}</strong> {{ object.assinado_por.get_full_name|default:object.assinado_por.username }}</p>
{% endif %}
{% for assinatura in assinaturas %}
<divclass="{% if not forloop.last %}mb-2 pb-2 border-bottom{% endif %}">
<divclass="row">
<divclass="col-md-6">
<pclass="mb-1"><strong>{% trans "Assinado por:" %}</strong> {{ assinatura.nome_assinante }}</p>
<pclass="mb-1"><strong>{% trans "Data/Hora:" %}</strong> {{ assinatura.data_assinatura }}</p>
</div>
<divclass="col-md-6">
{% if object.assinatura_info %}
<pclass="mb-1"><strong>{% trans "Tipo de Certificado:" %}</strong> {{ object.assinatura_info.tipo_certificado|default:"A1" }}</p>
{% if object.assinatura_info.subject %}
<pclass="mb-1"><strong>{% trans "Certificado:" %}</strong> {{ object.assinatura_info.subject|truncatechars:50 }}</p>
{% endif %}
{% if object.assinatura_info.valid_to %}
<pclass="mb-1"><strong>{% trans "Validade:" %}</strong> {{ object.assinatura_info.valid_to|slice:":10" }}</p>
{% endif %}
<pclass="mb-1"><strong>{% trans "Tipo de Certificado:" %}</strong> {{ assinatura.tipo_certificado_display|default:assinatura.tipo_certificado|default:"A1" }}</p>
{% if assinatura.cargo %}
<pclass="mb-1"><strong>{% trans "Cargo:" %}</strong> {{ assinatura.cargo }}</p>
{% endif %}
</div>
</div>
</div>
{% empty %}
{% if object.assinado_por %}
<pclass="mb-1"><strong>{% trans "Assinado por:" %}</strong> {{ object.assinado_por.get_full_name|default:object.assinado_por.username }}</p>
{% endif %}
{% if object.assinado_em %}
<pclass="mb-1"><strong>{% trans "Data/Hora:" %}</strong> {{ object.assinado_em|localtime|date:"d/m/Y H:i:s" }}</p>