Metadata-Version: 2.4
Name: veevatools
Version: 1.0.2
Summary: Veeva tools library for accelerating Veeva Systems Internal Tools development
Author-email: Michael Pay <monickenish@gmail.com>
License: Copyright (c) 2025 Veeva Systems, Inc.
        All Rights Reserved
        
        Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
        and associated documentation files (the "Software"), to deal in the Software without restriction, 
        including without limitation the rights to use, copy, modify, merge, publish, distribute, 
        sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in 
        all copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
        BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
        NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
        DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
        
        ---------------------------------------------------------------------------
        Third-Party Licenses:
        
        This software includes, depends on, or is otherwise derived from the following third-party libraries.
        Each listed library is governed by its own license, which is separate and distinct from the license 
        above. By using this software, you agree to comply with the terms of these third-party licenses.
        
        - **pandas (BSD-3-Clause)**  
          License: [https://github.com/pandas-dev/pandas/blob/main/LICENSE](https://github.com/pandas-dev/pandas/blob/main/LICENSE)
        
        - **simple-salesforce (Apache License 2.0)**  
          License: [https://github.com/simple-salesforce/simple-salesforce/blob/master/LICENSE.txt](https://github.com/simple-salesforce/simple-salesforce/blob/master/LICENSE.txt)
        
        - **salesforce-bulk (MIT)**  
          License: [https://pypi.org/project/salesforce-bulk/](https://pypi.org/project/salesforce-bulk/)
        
        - **sfdclib (MIT)**  
          License: [https://pypi.org/project/sfdclib/](https://pypi.org/project/sfdclib/)
        
        - **openpyxl (MIT)**  
          License: [https://foss.heptapod.net/openpyxl/openpyxl/-/blob/branch/3.1/LICENSE](https://foss.heptapod.net/openpyxl/openpyxl/-/blob/branch/3.1/LICENSE)
        
        - **zeep (MIT)**  
          License: [https://github.com/mvantellingen/python-zeep/blob/master/LICENSE](https://github.com/mvantellingen/python-zeep/blob/master/LICENSE)
        
        - **aiosignal (MIT)**  
          License: [https://github.com/aio-libs/aiosignal/blob/main/LICENSE](https://github.com/aio-libs/aiosignal/blob/main/LICENSE)
        
        - **aiohttp (Apache License 2.0)**  
          License: [https://github.com/aio-libs/aiohttp/blob/main/LICENSE](https://github.com/aio-libs/aiohttp/blob/main/LICENSE)
        
        - **pyarrow (Apache License 2.0)**  
          License: [https://github.com/apache/arrow/blob/master/LICENSE.txt](https://github.com/apache/arrow/blob/master/LICENSE.txt)
        
        - **psycopg2-binary (LGPL-3.0-only)**  
          License: [https://github.com/psycopg/psycopg2/blob/master/LICENSE](https://github.com/psycopg/psycopg2/blob/master/LICENSE)
        
        - **beautifulsoup4 (MIT)**  
          License: [https://www.crummy.com/software/BeautifulSoup/bs4/doc/](https://www.crummy.com/software/BeautifulSoup/bs4/doc/)
        
        - **boto3 (Apache License 2.0)**  
          License: [https://github.com/boto/boto3/blob/develop/LICENSE](https://github.com/boto/boto3/blob/develop/LICENSE)
        
        
        Where required, the full text of the above licenses can be found at the provided links or within 
        their respective source distributions.
        
        ---------------------------------------------------------------------------
        
        End of License File
Project-URL: Homepage, https://github.com/michaelpay
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Requires-Dist: requests>=2.28.0
Provides-Extra: salesforce
Requires-Dist: simple-salesforce>=1.11.6; extra == "salesforce"
Requires-Dist: salesforce-bulk>=2.2.0; extra == "salesforce"
Requires-Dist: sfdclib>=0.2.26; extra == "salesforce"
Requires-Dist: zeep<5.0.0,>=4.1.0; extra == "salesforce"
Requires-Dist: openpyxl<4.0.0,>=3.1.2; extra == "salesforce"
Requires-Dist: numpy; extra == "salesforce"
Requires-Dist: pandas>=1.4.2; extra == "salesforce"
Requires-Dist: beautifulsoup4<5.0.0,>=4.11.1; extra == "salesforce"
Provides-Extra: vault
Provides-Extra: network
Provides-Extra: nitro
Requires-Dist: psycopg2-binary<3.0.0,>=2.9.9; extra == "nitro"
Requires-Dist: sqlalchemy; extra == "nitro"
Provides-Extra: all
Requires-Dist: veevatools[network,nitro,salesforce,vault]; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: tox; extra == "dev"
Requires-Dist: black; extra == "dev"
Requires-Dist: flake8; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Requires-Dist: pytest-asyncio; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: pytest-mock; extra == "dev"
Requires-Dist: playwright; extra == "dev"
Dynamic: license-file

[![Downloads](https://pepy.tech/badge/veevatools)](https://pepy.tech/project/veevatools)

# Introduction

This python package is a set of Salesforce.com, Veeva Network, Veeva Vault, and Veeva Nitro libraries, scripts, and functions used to help expedite the development of Veeva Tools.
<br/>
<br/>

# Installation / Requirements

Ensure you have **at least Python version 3.10** installed.
To Check your installation version, type the following commands in the terminal (MacOs) / command prompt (Windows):
```
python --version
```
To install python, go to https://www.python.org/ then navigate to the download page of your Operating System.

![Screenshot 2022-06-24 140724](https://user-images.githubusercontent.com/59848012/175649491-0eafdef7-acd2-4631-85cb-f9dee8630b04.png)

You will need to have Packager Installer for Python (pip) installed. To install pip, run the following command in the terminal (MacOs) / command prompt (Windows):

```
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python3 get-pip.py
```
To install the Veeva Tools library:

```
pip install veevatools
```
To upgrade to the latest version of Veeva Tools library:
```
pip install veevatools --upgrade
```

## Installation Options

Install only the modules you need:

```bash
# Install everything
pip install veevatools[all]

# Install individual modules
pip install veevatools[vault]        # Veeva Vault only
pip install veevatools[salesforce]   # Salesforce/CRM only
pip install veevatools[network]      # Veeva Network only
pip install veevatools[nitro]        # Veeva Nitro only

# Development dependencies
pip install veevatools[dev]
```

# Overview

The Veeva Tools package currently contains 4 major components:
## Salesforce library

### Authentication:

```python
from veevatools.salesforce import Sf
import pandas as pd

sf = Sf()
sf.authenticate(
    sfUsername='yourname@salesforce.com',
    sfPassword='password123',
    sfOrgId='00D2C0000008jIK',
    is_sandbox=False
    )
```
> Sidenote on Pandas DataFrames: <br/>
Pandas DataFrame (pd) is used to prepare the data for import (i.e. create, update methods) and additional export methods such as pd.to_excel() in order to save the output into an Excel file.<br/>
Additionally, Complex data manipuation (joins, merges, groupbys, filters)and data analytics (describe, statistical analysis) can all be performed using Pandas. <br />
To learn more about Pandas DataFrames, go to the [Pandas documentation](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html)
<br \>
> Or just Google tutorials on Pandas DataFrames.
[This YouTube playlist by Corey Schafer](https://www.youtube.com/watch?v=ZyhVh-qRZPA&list=PL-osiE80TeTsWmV9i9c58mdDCSskIFdDS&ab_channel=CoreySchafer)
provides an excellent starting point into the world of Pandas!

<br/>

### Data methods:
The salesforce class (Sf) contains methods that can help you interact with data and metadata components:
<br/>
#### **Query**

```python
account_recordtypes = sf.query("SELECT Id, Name, SobjectType from RecordType WHERE SobjectType = 'Account'")

account_recordtypes
```

`Return -> pd.DataFrame():`
|    |                 Id |                      Name | SobjectType |
|---:|-------------------:|--------------------------:|------------:|
|  0 | 012f4000001ArT3AAK |          Professional_vod |     Account |
|  1 | 012f4000001ArT4AAK |           Institution_vod |     Account |
|  2 | 012f4000001ArT5AAK |                   MCO_vod |     Account |
|  3 | 012f4000001ArT6AAK |          Organization_vod |     Account |
|  4 | 012f4000001ArWzAAK |              Hospital_vod |     Account |

> Sidenote: <br />
You can use any Pandas (pd) methods on the return value of the query output. For example <br/>```account_recordtypes.to_excel("Account RecordTypes.xlsx")``` <br/>
Will save the results of the DataFrame into an Excel file.

<br/>

### **Create**
```python
## Takes a DataFrame of CRM records and creates records in CRM

account_records = pd.DataFrame([{'FirstName': 'Test', 'LastName': 'Account'}, {'FirstName': 'Test2', 'LastName': 'Account2'}])

result = sf.create('Account', account_records)

result
```
`Return -> pd.DataFrame():`
|   | success | created |                 Id |
|--:|--------:|--------:|-------------------:|
| 0 |    True |    True | 0010r00000tF7L1AAK |
| 1 |    True |    True | 0010r00000tF7L2AAK |

<br/>

### Update
```python
### Takes a dataframe that contains at least the Id column
### and any other column to be updated, for example, FirstName
update_account_name = pd.DataFrame(
    [{'FirstName': 'Updated', 'Id': '0010r00000tF7L1AAK'},
     {'FirstName': 'Name', 'Id': '0010r00000tF7L2AAK'}]
    )

result = sf.update('Account', update_account_name)

result
```
`Return -> pd.DataFrame()`
|   | success | created |                 Id |
|--:|--------:|--------:|-------------------:|
| 0 |    True |   False | 0010r00000tF7L1AAK |
| 1 |    True |   False | 0010r00000tF7L2AAK |
<br/>

### Upsert
```python
### Takes a dataframe that contains an external ID column
### and any other column to be updated, for example, Name
### if the external ID matches an existing record,
### the account is updated, otherwise, a new record is created

upsert_account = pd.DataFrame(
    [{'NET_External_Id__c': '242977178138969088', 'Name': 'Updated Hospital Name'},
     {'NET_External_Id__c': '555579769212255555', 'Name': 'Create New Hospital'}]
    )

result = sf.upsert(object_api='Account', external_id_field_api='NET_External_Id__c', record_dataframe=upsert_account)

result
```
`Return -> pd.DataFrame()`
|   | success | created |                 id |
|--:|--------:|--------:|-------------------:|
| 0 |    True |   False | 001f400000PKOrwAAH |
| 1 |    True |    True | 0010r00000tF7stAAC |

<br/>

### Delete
```python
### Takes a dataframe that contains the Id column
### deletes records listed based on their SFID.

delete_account = pd.DataFrame([{'Id': '0010r00000tF7stAAC'}, {'Id': '001f400000PKOrwAAH'}])

result = sf.delete(object_api='Account', record_dataframe=delete_account)

result
```
`Return -> pd.DataFrame()`

|   | success | created |                 Id |
|--:|--------:|--------:|-------------------:|
| 0 |    True |   False | 0010r00000tF7stAAC |
| 1 |    True |   False | 001f400000PKOrwAAH |

<br/>

### Metadata Methods

Metadata methods (Read, Create, Update, Rename, Delete, List) -- coming soon.

<br/>

## Vault library

### Authentication:

```python
from veevavault import VaultClient, DocumentService

client = VaultClient()
client.authenticate(vaultURL='https://myvault.veevavault.com', vaultUserName='user@vault.com', vaultPassword='password123')

# Services take the authenticated client as their argument
docs = DocumentService(client)
all_docs = docs.retrieval.retrieve_all_documents()
```

<br/>

## Network library

### Authentication:

```python
from veevanetwork import NetworkClient

# NetworkClient requires url, username, and password at construction
client = NetworkClient(
    url='https://mynetwork.veevanetwork.com',
    username='user',
    password='pass',
)
client.authenticate()

# Services are accessed as properties on the client
results = client.search.search(q='Smith')
objects = client.metadata.retrieve_object_types()
```

<br/>

## Nitro library

### Authentication:

```python
from veevanitro import Nitro

# Nitro wires the client and all services together
n = Nitro()
n.auth.login(server_url='https://mycompany.veevanitro.com', username='user', password='pass')

# Access services directly
tenant = n.admin.get_tenant()
users = n.admin.get_users()
```
