mdsol / rwslib

Provide a (programmer) friendly client library to Rave Web Services (RWS).
MIT License
31 stars 13 forks source link

audit_event: rwslib.extras, how to fetch datapage_name and Log# #105

Closed champ16 closed 3 years ago

champ16 commented 4 years ago

I am working on audit data using audit_event. I want to fetch audit records for Entered and DataChanged event. I am able to get all the desired column except datapage_name. Can you please guide me on how I can get that. I have used below code-

class Subjects(object): def init(self): self.subjects = []

def Entered(self, context):
    """Capture the Entered event"""
    self.study_oid = context.study_oid
    self.subcategory = context.subcategory
    self.subject_name= context.subject.name
    self.event = context.event.oid
    self.event_rpt=context.event.repeat_key
    self.form_oid = context.form.oid
    **self.form_n=context.form.datapage_name**---this is not working.
    self.form_rpt=context.form.repeat_key

Additionally, If I want to add log #(0, for standard form and respective log position for Log forms) for the each record. how I can achieve that.

Thanks a lot.

iansparks commented 4 years ago

Actually, it looks from the docs like datapage_name is not provided by the standard output. Although, datapage_id is provided and that doesn't appear in the example either.

But there are different versions of the ODM adapter ClinicalRecordsDataSet. You might want to check if you have the latest installed on your URL.

  <ClinicalData StudyOID="Mediflex(Prod)" MetaDataVersionOID="18" mdsol:AuditSubCategoryName="Entered">
    <SubjectData SubjectKey="3bddb79c-0023-47bb-8861-5345f8987c7e" mdsol:SubjectKeyType="SubjectUUID" mdsol:SubjectName="123 AB">
      <SiteRef LocationOID="12345"/>
      <StudyEventData StudyEventOID="SUBJECT">
        <FormData FormOID="EN" FormRepeatKey="1">
          <ItemGroupData ItemGroupOID="EN">
            <ItemData ItemOID="EN.USUBJID" TransactionType="Upsert" Value="123 AB">
              <AuditRecord>
                <UserRef UserOID="systemuser"/>
                <LocationRef LocationOID="12345"/>
                <DateTimeStamp>2009-12-01T15:27:46</DateTimeStamp>
                <ReasonForChange/>
                <SourceID>823</SourceID>
              </AuditRecord>
            </ItemData>
          </ItemGroupData>
        </FormData>
      </StudyEventData>
    </SubjectData>
  </ClinicalData>

For recordposition, I would expect that the ItemGroup RepeatKey would be present with a value > 0 if it was a log record. e.g.


    def Entered(self, context):
        if context.itemgroup.repeat_key > 0:
            print(context.itemgroup)
champ16 commented 4 years ago

Yes you are right, Datapage Name is not been provided by standard output. Datapage ID is present but I do not need it in my report. My question is what I should do in order to get the DataPage name for the correspond form_oid, datapage_id. Below is the output from request-

class Subjects(object): def init(self): self.subjects = []

def Entered(self, context):
    """Capture the Entered event"""
    self.study_oid = context.study_oid
    self.subcategory = context.subcategory
    self.subject_name= context.subject.name
    self.event = context.event.oid
    self.event_rpt=context.event.repeat_key
    self.form_oid = context.form.oid
    self.form_name=context.form.datapage_name
    self.form_rpt=context.form.repeat_key
    self.field=context.item.oid
    self.value=context.item.value
    self.site= context.audit_record.location_oid
    self.audit_time=context.audit_record.datetimestamp
    list1=[self.study_oid,self.subcategory,self.subject_name,self.event,
           self.event_rpt,self.form_oid,self.form_name,self.form_rpt,self.field,
           self.value, self.site,self.audit_time]
    self.subjects.append(list1)

subjects = Subjects()

Make a connection

c = RWSConnection("bsc-cf","XXXXXX","XXXXXXX")

Pass connection and counter to the ODMAdapter along with the study name/environment we want to process

o = ODMAdapter(c, "**","*****", subjects)

Run the adapter

o.run(start_id=0, per_page=10000, max_pages=1) print(subjects.subjects)

Audit= pd.DataFrame(subjects.subjects) print(Audit.head()) Audit.to_csv(r'C:\Users\kumap22\Desktop\audit.csv', index=False)

iansparks commented 4 years ago

I don't know of a datapage-id-to-name conversion recordset. Based on the MetaDataVersion="{number}" attribute at the top of the file you could find out the name of the Form based on the OID from one of the ODM Metadata extracts. i.e. you get the ODM Metadata for the study design, find the Form OID and get the FormName.

But since DataPages (forms) can change name you would still need to know when the form changes name. You might be able to get that with:

    def ObjectNameChanged(self, context):
        print(context) 
champ16 commented 4 years ago

Thanks a lot Ian..I will use Form metadata and and merge with my report.

Thanks for quick response.

glow-mdsol commented 4 years ago

It looks like the documentation on learn.mdsol.com is out of date on this. I'll follow up to make sure the examples are more representative

champ16 commented 4 years ago

It worked. Thank you!!

I have one more question: in order to pull data in batch we have to initialize start_id with last run max_id. And max_id will hold data for the last record read for a particular subcategory.

If i am reading data for multiple subcategory how I can handle max_id. one way of doing it is to pull source ID for all the record and get the last source ID as max_id. max_id = subjects.subjects[-1][-1]

I am not sure if this is the way to do it. let me know if any better way to do it

iansparks commented 4 years ago

The context gets every audit number in:

context.audit_record.source_id

So you can track the last audit you looked at :

class SubjectCounter(object):

    def __init__(self):
        self.count = 0
        self.last_audit = 0

    def SubjectCreated(self, context):
        self.count += 1
        print(context.audit_record.source_id)
        self.last_audit = context.audit_record.source_id

    def default(self, context):
        print(context.audit_record.source_id)
        self.last_audit = context.audit_record.source_id

At the end your object will have the last_audit id that was last seen. The "default" method runs for every audit event that you don't have a specific handler for (e.g. SubjectCreated) so it captures every other message (default() does not get called for handlers that you DO define so it will never see SubjectCreated events if you have a SubjectCreated handler defined)

Alternatively, if you just want to start from the last subject created event then just capture the last_audit number in that handler.

I hope this makes sense.

glow-mdsol commented 3 years ago

@champ16 - ok to close this?

iansparks commented 3 years ago

It's been two months. Closing. If this is still an issue, @champ16 can re-open.