Giter VIP home page Giter VIP logo

django-docusign's Introduction

Build Status Documentation Status Pypi Status

django-docusign

django-docusign is a Django application for DocuSign's digital signature SAAS platform.

It uses pydocusign as Python client. It implements django-anysign API.

Project status

django-docusign is under active development. The project is not mature yet, but authors already use it! It means that, while API and implementation may change (improve!) a bit, authors do care of the changes.

Also, help is welcome! Feel free to report issues, request features or refactoring!

Resources

django-docusign's People

Contributors

benoitbryon avatar bersace avatar hsmett avatar joehybird avatar kbussell avatar morganead avatar mrjmad avatar sheb avatar smcoll avatar zebuline avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-docusign's Issues

default 'anysign' url namespace not documented

The documentation didn't indicate that the callback url needs to be namespaced as 'anysign' by default. i suppose the only way to override this is to subclass the backend and reference it in settings.ANYSIGN['BACKENDS']? Perhaps the namespace could be a setting.

Reverse match failed for 'signer'

I try to use this app in the context of my project, and I have to log in and sign a document in a iFrame (or web view), inside my app.
I checked your demo, and I understood the most part of the code.

Unfortunately, I have big troubles using a custom namespace for my Django app, as the default namespace for DocuSign components is 'anysign'.
Also, I have troubles in getting the absolute URL, for a given signer, in order to get my web view.

In home.html, I have the same code of your demo:

... 
{% for signer in signature.signers.all %}
        <li>{{ signer.email }} =&gt; <a href="{{ signer.get_absolute_url }}">sign</a> [{{ signer.status }}{% if signer.status_datetime %} {{signer.status_datetime }}{% endif %}{% if signer.status_details %} {{signer.status_details }}{% endif %}]</li>
{% endfor %}
...

The problem in this code is {{ signer.get_absolute_url }}. Indeed, this code will call the get_absolute_url method of the signer object, from django-anysign.
Using this code, I have the following error:

NoReverseMatch at /
Reverse for 'signer' not found. 'signer' is not a valid view function or pattern name.

I don't understand this error because I set my URLs correctly (I think) in urls.py, like this:

anysign_patterns = [
    url(r'^signer/(?P<pk>\d+)/$', signer_view, name='signer'),
    url(r'^signer/(?P<pk>\d+)/return/$',
        signer_return_view,
        name='signer_return'),
    url(r'^signer/(?P<pk>\d+)/canceled/$',
        signer_canceled_view,
        name='signer_canceled'),
    url(r'^signer/(?P<pk>\d+)/error/$',
        signer_error_view,
        name='signer_error'),
    url(r'^signer/(?P<pk>\d+)/declined/$',
        signer_declined_view,
        name='signer_declined'),
    url(r'^signer/(?P<pk>\d+)/signed/$',
        signer_signed_view,
        name='signer_signed'),
]

urlpatterns = [
    url(r'^$', home_view, name='home'),
    url(r'^signature/add/$', create_signature_view, name="create_signature"),
    url(r'', include((anysign_patterns, 'anysign'), namespace='anysign')),
]

and the signer_view is a view from a class in views.py, like your demo.

I don't understand why I have this issue calling a method for the signer object...
Is there some "black magic" inside, or something I don't fully understand (I think this is the solution of my problem :) ).
Thanks in advance!

create_signature without subject and blurb causes 400

DocuSign's API returns a 400 when a subject or blurb are not present in the envelope creation call. For this reason, i propose that we make them required arguments in the create_signature function. That would change the function's signature, so may be backwards incompatible, but otherwise create_signature(obj) will fail every time.

pydocusign.DocuSignClient reads defaults in settings.DOCUSIGN

As a developer and django-docusign user, in order to share DocuSign configuration across several views/forms/models... in code, I want to write the shared configuration once in Django settings, and have pydocusign.DocuSignClient initialized with these settings.

See https://github.com/novapost/pydocusign/blob/0.11/pydocusign/client.py#L21-L29
pydocusign.DocuSignClient initialization takes several arguments => allow developer to define them in DOCUSIGN dictionary.

Example in settings.py:

DOCUSIGN = {
    root_url: 'https://demo.docusign.net/restapi/v2',
    integrator_key: 'some-secret-integrator-key',
}

docs don't mention that docusign_template_id is required

i see the docusign_template_id exists on the SignatureType model in the demo, but the backend itself references this property that won't exist on an existing model unless explicitly added. This results in an AttributeError. Perhaps the docs ought to mention this, or perhaps the backend should handle cases where it doesn't exist, which seems sufficient given that the model field in the demo accepts empty strings.

unhandled signer event in callback view when using routing order

The callback view only processes the most recent recipient event in a callback payload. In the case of signing order, though, a signer marked as "Completed" is reported as a simultaneous event along with the next signer's "Sent" event in the ordering. This means the callback view misses the first signer's event.

Here are the RecipientStatuses sections of two subsequent callback requests, to illustrate:

Callback request for a "Delivered" status for the first signer:

<RecipientStatus>
    <Type>Signer</Type>
    <Email>[email protected]</Email>
    <UserName>First Signer</UserName>
    <RoutingOrder>1</RoutingOrder>
    <Sent>2016-11-14T15:42:29.037</Sent>
    <Delivered>2016-11-14T15:45:46.667</Delivered>
    <DeclineReason xsi:nil="true"/>
    <Status>Delivered</Status>
    <RecipientIPAddress>1.1.1.1</RecipientIPAddress>
    <ClientUserId>17</ClientUserId>
    <CustomFields/>
    <AccountStatus>Active</AccountStatus>
    <RecipientId>1aa6002b-5d93-4549-a45f-7e5906327d9e</RecipientId>
</RecipientStatus>
<RecipientStatus>
    <Type>Signer</Type>
    <Email>[email protected]</Email>
    <UserName>Second Signer</UserName>
    <RoutingOrder>2</RoutingOrder>
    <DeclineReason xsi:nil="true"/>
    <Status>Created</Status>
    <RecipientIPAddress/>
    <ClientUserId>18</ClientUserId>
    <CustomFields/>
    <AccountStatus>Active</AccountStatus>
    <RecipientId>f599463d-8172-40ae-9e38-c004bdfcd9a8</RecipientId>
</RecipientStatus>

Callback request for a "Completed" status for the first signer:

<RecipientStatus>
    <Type>Signer</Type>
    <Email>[email protected]</Email>
    <UserName>First Signer</UserName>
    <RoutingOrder>1</RoutingOrder>
    <Sent>2016-11-14T15:42:29.037</Sent>
    <Delivered>2016-11-14T15:45:46.667</Delivered>
    <Signed>2016-11-14T15:46:13.153</Signed>
    <DeclineReason xsi:nil="true"/>
    <Status>Completed</Status>
    <RecipientIPAddress>1.1.1.1</RecipientIPAddress>
    <ClientUserId>17</ClientUserId>
    <CustomFields/>
    <TabStatuses>
        <TabStatus>
            <TabType>SignHere</TabType>
            <Status>Signed</Status>
            <XPosition>227</XPosition>
            <YPosition>338</YPosition>
            <DocumentID>1</DocumentID>
            <PageNumber>1</PageNumber>
        </TabStatus>
    </TabStatuses>
    <AccountStatus>Active</AccountStatus>
    <RecipientId>1aa6002b-5d93-4549-a45f-7e5906327d9e</RecipientId>
</RecipientStatus>
<RecipientStatus>
    <Type>Signer</Type>
    <Email>[email protected]</Email>
    <UserName>Second Signer</UserName>
    <RoutingOrder>2</RoutingOrder>
    <Sent>2016-11-14T15:46:13.653</Sent>
    <DeclineReason xsi:nil="true"/>
    <Status>Sent</Status>
    <RecipientIPAddress/>
    <ClientUserId>18</ClientUserId>
    <CustomFields/>
    <AccountStatus>Active</AccountStatus>
    <RecipientId>f599463d-8172-40ae-9e38-c004bdfcd9a8</RecipientId>
</RecipientStatus>

Look what happens when pydocusign. parses the recipient events in the last request:

>>> from pydocusign.parser import DocuSignCallbackParser
>>> p = DocuSignCallbackParser(xml_payload)
>>> p.recipient_events
[{'clientUserId': u'17',
  'datetime': datetime.datetime(2016, 11, 14, 15, 42, 29, 37000, tzinfo=tzoffset(None, -28800)),
  'recipient': u'17',
  'recipientId': u'1aa6002b-5d93-4549-a45f-7e5906327d9e',
  'status': 'Sent'},
 {'clientUserId': u'17',
  'datetime': datetime.datetime(2016, 11, 14, 15, 45, 46, 667000, tzinfo=tzoffset(None, -28800)),
  'recipient': u'17',
  'recipientId': u'1aa6002b-5d93-4549-a45f-7e5906327d9e',
  'status': 'Delivered'},
 {'clientUserId': u'17',
  'datetime': datetime.datetime(2016, 11, 14, 15, 46, 13, 153000, tzinfo=tzoffset(None, -28800)),
  'recipient': u'17',
  'recipientId': u'1aa6002b-5d93-4549-a45f-7e5906327d9e',
  'status': 'Signed'},
 {'clientUserId': u'18',
  'datetime': datetime.datetime(2016, 11, 14, 15, 46, 13, 653000, tzinfo=tzoffset(None, -28800)),
  'recipient': u'18',
  'recipientId': u'f599463d-8172-40ae-9e38-c004bdfcd9a8',
  'status': 'Sent'}]

The "Completed" event on the first signer is not the last event in the order, so it is not processed; only the "Sent" event for the second signer is processed.

Any ideas on a graceful way to handle this problem? i wonder if there'd be even more missing events if there were multiple recipients sharing the latter signing order, since they'd probably all be sent at once.

recipient name change not captured in callback view

If a recipient changes their own name when signing, DocuSign updates that recipient's name in the subsequent DocuSign Connect requests. The DocuSignCallbackView doesn't capture this change, which means a later DocuSign client request which uses the recipient's name (for example, post_recipient_view) will fail with an UNKNOWN_ENVELOPE_RECIPIENT error like this:

DocuSignException: DocuSign request failed: POST https://na2.docusign.net/restapi/v2/accounts/<account-id>/envelopes/<envelope_id>/views/recipient returned code 400 while expecting code 201; Message: {  
  "errorCode": "UNKNOWN_ENVELOPE_RECIPIENT",  
  "message": "The recipient you have identified is not a valid recipient of the specified envelope."  
} ;

Seems to me we want to handle a potential name change in the callback view.

demo uses v2 of API, but pydocusign does not support v2 yet

i wrote an app using this library based on the assumption that v2 of the API was supported (based on the implementation in the demo). Reverting to v1 is causing regressions. This app's demo should probably be tested against v1, to prevent further confusion.

some code in SignatureCallbackView.post() is never reached

The if expression here will always return true, because the list comprehension only returns a list of True values. PR incoming.

            if all([True
                    for signer_event in self.docusign_parser.recipient_events
                    if signer_event['status'] == 'sent']):
                signer_events = self.docusign_parser.recipient_events
            # Else, do not care about "sent" event for signature.
            else:
                signature_event = None
                signer_events = [self.docusign_parser.recipient_events[-1]]

NoReverseMatch on get_signature_callback_url

It seems that django_anysign's implementation of get_signature_callback_url() uses the signature pk as an argument. django_docusign doesn't override that. But neither the callback view in the package nor the demo take a pk argument. So a NoReverseMatch is raised.

KeyError at /signature/add/ 'name' on demo

I am checking out the demo. I have created a sandbox account on the DocuSign site. I have stored those credentials under Change DocuSign settings .
I am trying to Create signature . I choose the document I want to upload, on the name field I type "DanaeVogiatzi" and on the e-mail field I type the same e-mail as I my DocuSign account.

In the database the records are being created. Each row misses the signature_backend_id and is saved as draft.

I am totally new on this digital signing thing ,so I am still trying to figure out how it works.

Am i doing something wrong? Should I make any extra settings on the Docusign site?

Thanks!

Django 1.8 support/documentation

Is there support for 1.8? I saw there was a ticket opened for 1.7 from the fall of 2014. This would be extremely helpful for a specific project I am working on.

Also it would be nice if the documentation included a basic example of how to get up an running.

For my project I need to have customers sign a contract to use a service. So something a long the lines of creating a document, having the user sign that document, then updating a database table entry that they have completed it, would be extremely helpful. Doesn't have to be exact to my needs, but I'm sure other potential users would benefit from a little hand holding as well.

Please let me know if more information could be published or is available else where. Thank you for your time.

update_signer and update_signature are badly triggered in some cases

Cases in SignatureCallbackView:

  • when signature is created, DocuSign sends one callback where signature=sent and all signers are "sent" too. At the moment, update_signature() is triggered and only last signer receives update_signer(). Should be all signers receive update_signer()
  • when signer signs document, but there are signers left, DocuSign callback does not mentions signature change (still "sent", or perhaps "delivered") and of course signer is "signed". At the moment, both update_signature() and update_signer() are triggered. Should be only update_signer().

post_recipient_view explication

I try to understand how to customize this Django module, based on my case:

  1. The creator of the document will create, using XXX/views/sender, the tabs;
  2. The signer will fill the blanks and sign only the document, pre-processed by the creator.

So, in this example, I have two distinct users:

  • the creator of the document, who can edit the tabs,
  • the signer, who can fill the blanks and sign the documents.

In the model, we have only one user model: Signer.
Is Signer is supposed to be the creator and the signer of the document?

Also, do you have any idea how to to restrict the possibilities (to edit/modify tabs and signature) for both the creator and the signer?
I checked the code of the module, and I found that the post_recipient_view method calls only XXX/views/recipient, and not XXX/views/sender.
So can we consider the Signer model as a recipient only?

Thanks in advance, and thanks for this awesome work :)

new release

The most recent release to PyPI was v0.12 on 2015-09-10. There have been 8 merged PRs since then; could we issue a v0.13 release?

View : DocuSign API callback

Implement utilities to handle DocuSign Connect's callbacks, i.e. eventNotification arguments in "create envelope" function. See https://www.docusign.com/p/RESTAPIGuide/RESTAPIGuide.htm#REST%20API%20References/Send%20an%20Envelope.htm

Context in workflow:

  • Signature has been created
  • Signature is updated => DocuSign Connect sends an "eventNotification"
  • django-docusign (generic) view receives the callback and processes the document

The view should be generic: provide bits to handle the DocuSign's request, but let the developer implement custom stuff to update the signature and trigger business-specific operations.

Verify Callback Events

I might be missing something, but is there anything currently implemented that verifies callback (POST) events actually originate from Docusign?

allow Makefile to import environment variables from a .env

Feature request: as a developer, i'd like to be able to copy an empty .env-sample, save it as an ignored .env-local file, fill in some values, and be able to run make test without any environment variable-setting prefix.

i know it doesn't solve for a few tests that require a callback url to be deployed remotely.

Passing arbiratry data to Docusign Template

I'm trying to fill an "address" field in my docusign template prior to signing. Passing data was already discussed here.

But its not clear whether the support is actually working and how I would go about this. (Added variable to template and tried passing parameter, that didnt work).

 def create_signature(self, signature):
        """Create signature backend-side."""
        params = {'address': 'Home Street'}
        if self.signature_backend.use_callback:
            params['callback_url'] = self.cleaned_data['callback_url']
        self.signature_backend.create_signature(
            signature,
            subject=signature.document_title,
            **params
        )

OperationalError when running `make demo`

$ make demo
[...]
django.db.utils.OperationalError: unable to open database file

This appears to be caused by a missing /var/ directory in the project root at the time syncdb is run.

makemigrations creates unneeded migrations

The makemigrations management command will create a new migration for the model inheriting SignatureType whenever the keys in settings.ANYSIGN['BACKENDS'] change.

i think we need to make the function used for signature_backend_code.choices deconstructible

In demo, SettingsView updates session with wrong keys

In demo project:

So, there is something wrong somewhere in this implementation...

  • Write a test that shows the bug.
  • Fix the bug :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.